home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / src / redisplay.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-30  |  215.7 KB  |  7,501 lines

  1. /* Display generation from window structure and buffer text.
  2.    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
  3.    Copyright (C) 1995 Amdahl Corporation.
  4.    Copyright (C) 1995 Ben Wing.
  5.  
  6. This file is part of XEmacs.
  7.  
  8. XEmacs is free software; you can redistribute it and/or modify it
  9. under the terms of the GNU General Public License as published by the
  10. Free Software Foundation; either version 2, or (at your option) any
  11. later version.
  12.  
  13. XEmacs is distributed in the hope that it will be useful, but WITHOUT
  14. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with XEmacs; see the file COPYING.  If not, write to the Free
  20. Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  21.  
  22. /* Synched up with:  Not in FSF. */
  23.  
  24. /* This file has been Mule-ized. */
  25.  
  26. /* Author: Chuck Thompson */
  27.  
  28. /*****************************************************************************
  29.  The Golden Rules of Redisplay
  30.  
  31.  First:        It Is Better To Be Correct Than Fast
  32.  Second:    Though Shall Not Run Elisp From Within Redisplay
  33.  Third:        It Is Better To Be Fast Than Not To Be
  34.  ****************************************************************************/
  35.  
  36. #include <config.h>
  37. #include "lisp.h"
  38.  
  39. #include "buffer.h"
  40. #include "commands.h"
  41. #include "debug.h"
  42. #include "device.h"
  43. #include "extents.h"
  44. #include "faces.h"
  45. #include "frame.h"
  46. #include "glyphs.h"
  47. #include "insdel.h"
  48. #include "process.h"
  49. #include "redisplay.h"
  50. #include "toolbar.h"
  51. #include "window.h"
  52.  
  53. /* Return value to indicate a failure by an add_*_rune routine to add
  54.    a rune, but no propagation information needs to be returned. */
  55. #define ADD_FAILED (prop_block_dynarr *) 1
  56.  
  57. #define BEGIN_GLYPHS    0
  58. #define END_GLYPHS    1
  59. #define LEFT_GLYPHS    2
  60. #define RIGHT_GLYPHS    3
  61.  
  62. /* Set the vertical clip to 0 if we are currently updating the line
  63.    start cache.  Otherwise for buffers of line height 1 it may fail to
  64.    be able to work properly because regenerate_window will not layout
  65.    a single line.  */
  66. #define VERTICAL_CLIP(w, display)                    \
  67.   (updating_line_start_cache                        \
  68.    ? 0                                    \
  69.    : ((WINDOW_IS_TTY (w) | (!display && scroll_on_clipped_lines))    \
  70.       ? INT_MAX                                \
  71.       : vertical_clip))
  72.  
  73. /*
  74.  * Prototypes for all functions defined in redisplay.c.
  75.  */
  76. struct display_block *get_display_block_from_line (struct display_line *dl,
  77.                            enum display_type type);
  78. layout_bounds calculate_display_line_boundaries (struct window *w,
  79.                          int modeline);
  80. static Bufpos generate_display_line (struct window *w, struct display_line *dl,
  81.                      int bounds, Bufpos start_pos,
  82.                      int start_col, prop_block_dynarr **prop,
  83.                      int type);
  84. static void generate_modeline (struct window *w, struct display_line *dl,
  85.                    int type);
  86. static prop_block_dynarr *add_emchar_rune (pos_data *data);
  87. static prop_block_dynarr *add_string_of_bufbyte_runes (pos_data *data,
  88.                                Bufbyte *c_string,
  89.                                Bytecount c_length,
  90.                                int no_prop);
  91. static prop_block_dynarr *add_string_of_emchar_runes (pos_data *data,
  92.                               Emchar *e_string,
  93.                               Bytecount e_length);
  94. static prop_block_dynarr *add_blank_rune (pos_data *data, struct window *w,
  95.                       int char_tab_width);
  96. static prop_block_dynarr *add_octal_runes (pos_data *data);
  97. static prop_block_dynarr *add_control_char_runes (pos_data *data,
  98.                           struct buffer *b);
  99. static prop_block_dynarr *add_disp_table_entry_runes (pos_data *data,
  100.                               Lisp_Object entry);
  101. static prop_block_dynarr *add_propagation_runes (prop_block_dynarr **prop,
  102.                          pos_data *data);
  103. static prop_block_dynarr *add_glyph_rune (pos_data *data,
  104.                       struct glyph_block *gb,
  105.                       int pos_type, int allow_cursor,
  106.                       struct glyph_cache_element *inst);
  107. static prop_block_dynarr *add_glyph_runes (pos_data *data,
  108.                        int pos_type);
  109. static Bufpos create_text_block (struct window *w, struct display_line *dl,
  110.                  Bufpos start_pos, int start_col,
  111.                  prop_block_dynarr **prop, int type);
  112. static int create_overlay_glyph_block (struct window *w,
  113.                        struct display_line *dl);
  114. static void create_left_glyph_block (struct window *w,
  115.                      struct display_line *dl,
  116.                      int overlay_width);
  117. static void create_right_glyph_block (struct window *w,
  118.                       struct display_line *dl);
  119. static void regenerate_window (struct window *w, Bufpos start_pos,
  120.                    Bufpos point, int type);
  121. static void regenerate_window_point_center (struct window *w, Bufpos point,
  122.                         int type);
  123. int window_half_pixpos (struct window *w);
  124. int line_at_center (struct window *w, int type);
  125. Bufpos point_at_center (struct window *w, int type, int regen, Bufpos start,
  126.             Bufpos point);
  127. static void redisplay_window (Lisp_Object window, int skip_selected);
  128. static void redisplay_windows (Lisp_Object window, int skip_selected);
  129. static int redisplay_frame (struct frame *f);
  130. void redisplay (void);
  131. static void decode_mode_spec (struct window *w, Emchar spec, int type);
  132. static void free_display_line (struct display_line *dl);
  133. void free_display_structs (struct window_mirror *mir);
  134. static int point_visible (struct window *w, Bufpos point, int type);
  135. static void update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
  136.                      Bufpos point, int no_regen);
  137. static Bufpos line_start_cache_start (struct window *w);
  138. static Bufpos line_start_cache_end (struct window *w);
  139.  
  140. /* This used to be 10 but 30 seems to give much better performance. */
  141. #define INIT_MAX_PREEMPTS    30
  142. static int max_preempts;
  143.  
  144. #define REDISPLAY_PREEMPTION_CHECK                \
  145.   do {                                \
  146.     preempted = 0;                        \
  147.     if (!disable_preemption &&                    \
  148.     ((preemption_count < max_preempts) || !NILP (Vexecuting_macro))) \
  149.       if (!INTERACTIVE || detect_input_pending ()) {        \
  150.         preempted = 1;                        \
  151.       }                                \
  152.   } while (0)
  153.  
  154. /*
  155.  * Redisplay global variables.
  156.  */
  157.  
  158. /* #### probably temporary */
  159. int cache_adjustment;
  160.  
  161. emchar_dynarr *mode_string_buffer;
  162. bufbyte_dynarr *mode_spec;
  163.  
  164. int in_display;        /* 1 if in redisplay.  */
  165.  
  166. int disable_preemption;    /* Used for debugging redisplay and for
  167.                force-redisplay. */
  168.  
  169. /* We only allow max_preempts preemptions before we force a redisplay. */
  170. static int preemption_count;
  171.  
  172. /* Minimum pixel height of clipped bottom display line. */
  173. int vertical_clip;
  174.  
  175. /* Minimum visible pixel width of clipped glyphs at right margin. */
  176. int horizontal_clip;
  177.  
  178. /* Set if currently inside update_line_start_cache. */
  179. int updating_line_start_cache;
  180.  
  181. /* Nonzero means reading single-character input with prompt
  182.    so put cursor on minibuffer after the prompt.  */
  183. int cursor_in_echo_area;
  184. Lisp_Object Qcursor_in_echo_area;
  185.  
  186. /* Nonzero means truncate lines in all windows less wide than the frame */
  187. int truncate_partial_width_windows;
  188.  
  189. /* non-nil if a buffer has changed since the last time redisplay completed */
  190. int buffers_changed;
  191. int buffers_changed_set;
  192.  
  193. /* non-nil if hscroll has changed somewhere or a buffer has been
  194.    narrowed or widened */
  195. int clip_changed;
  196. int clip_changed_set;
  197.  
  198. /* non-nil if any extent has changed since the last time redisplay completed */
  199. int extents_changed;
  200. int extents_changed_set;
  201.  
  202. /* non-nil if any face has changed since the last time redisplay completed */
  203. int faces_changed;
  204.  
  205. /* Nonzero means some frames have been marked as garbaged */
  206. int frame_changed;
  207.  
  208. /* This variable is 1 if the menubar widget has to be updated. 
  209.  It is set to 1 by set-menubar-dirty-flag and cleared when the widget
  210.  has been indapted. */
  211. /* indapted???? */
  212. int menubar_changed;
  213. int menubar_changed_set;
  214.  
  215. /* true iff we should redraw the modelines on the next redisplay */
  216. int modeline_changed;
  217. int modeline_changed_set;
  218.  
  219. /* non-nil if point has changed in some buffer since the last time
  220.    redisplay completed */
  221. int point_changed;
  222. int point_changed_set;
  223.  
  224. /* non-nil if some frame has changed its size */
  225. int size_changed;
  226.  
  227. /* non-nil if some device has signaled that it wants to change size */
  228. int asynch_device_change_pending;
  229.  
  230. /* non-nil if any toolbar has changed */
  231. int toolbar_changed;
  232. int toolbar_changed_set;
  233.  
  234. /* non-nil if any window has changed since the last time redisplay completed */
  235. int windows_changed;
  236.  
  237. /* non-nil if any frame's window struture has changed since the last
  238.    time redisplay completed */
  239. int windows_structure_changed;
  240.  
  241. /* If non-nil, use vertical bar cursor. */
  242. Lisp_Object Vbar_cursor;
  243.  
  244. /* #### All of the following crap is on probation. */
  245.  
  246.  
  247. int visible_bell;    /* If true and the terminal will support it
  248.                then the frame will flash instead of
  249.                beeping when an error occurs */
  250.  
  251. /* Nonzero means no need to redraw the entire frame on resuming
  252.    a suspended Emacs.  This is useful on terminals with multiple pages,
  253.    where one page is used for Emacs and another for all else. */
  254. int no_redraw_on_reenter;
  255.  
  256. Lisp_Object Vwindow_system;    /* nil or a symbol naming the window system
  257.                    under which emacs is running
  258.                    ('x is the only current possibility) */
  259. Lisp_Object Vinitial_window_system;
  260.  
  261. /* Version number of X windows: 10, 11 or nil.  */
  262. Lisp_Object Vwindow_system_version;
  263.  
  264. Lisp_Object Vglobal_mode_string;
  265. /* The number of lines to try scrolling a
  266.   window by when point leaves the window; if
  267.   it is <=0 then point is centered in the window */
  268. int scroll_step;
  269. /* Whether to display line numbers in the modeline. */
  270. int line_number_mode;
  271. /* Marker for where to display an arrow on top of the buffer text.  */
  272. Lisp_Object Voverlay_arrow_position;
  273. /* String to display for the arrow.  */
  274. Lisp_Object Voverlay_arrow_string;
  275.  
  276. /* #### END OF PROBATION */
  277.  
  278. #if 0
  279. /* #### Chuck says: I think this needs more thought.
  280.    Think about this for 19.14. */
  281. Lisp_Object Vpre_redisplay_hook, Vpost_redisplay_hook;
  282. Lisp_Object Qpre_redisplay_hook, Qpost_redisplay_hook;
  283. #endif
  284.  
  285. int last_display_warning_tick, display_warning_tick;
  286. Lisp_Object Qdisplay_warning_buffer;
  287. int inhibit_warning_display;
  288.  
  289. Lisp_Object Vleft_margin_width, Vright_margin_width;
  290. Lisp_Object Vminimum_line_ascent, Vminimum_line_descent;
  291. Lisp_Object Vuse_left_overflow, Vuse_right_overflow;
  292.  
  293.  
  294. /*****************************************************************************
  295.  get_display_block_from_line
  296.  
  297.  Return the display block from DL of the given TYPE.  A display line can have
  298.  only one display block of each possible type.  If DL does not have a block
  299.  of type TYPE, one will be created and added to DL.
  300.  ****************************************************************************/
  301. struct display_block *
  302. get_display_block_from_line (struct display_line *dl, enum display_type type)
  303. {
  304.   int elt;
  305.   struct display_block db;
  306.  
  307.   /* Check if this display line already has a block of the desired type and
  308.      if so, return it. */
  309.   if (dl->display_blocks)
  310.     {
  311.       for (elt = 0; elt < Dynarr_length (dl->display_blocks); elt++)
  312.     {
  313.       if (Dynarr_at (dl->display_blocks, elt).type == type)
  314.         return (Dynarr_atp (dl->display_blocks, elt));
  315.     }
  316.  
  317.       /* There isn't an active block of the desired type, but there
  318.          might still be allocated blocks we need to reuse. */
  319.       if (elt < Dynarr_largest (dl->display_blocks))
  320.     {
  321.       struct display_block *dbp = Dynarr_atp (dl->display_blocks, elt);
  322.  
  323.       /* 'add' the block to the list */
  324.       Dynarr_increment (dl->display_blocks);
  325.  
  326.       /* initialize and return */
  327.       dbp->type = type;
  328.       return dbp;
  329.     }
  330.     }
  331.   else
  332.     {
  333.       /* This line doesn't have any display blocks, so initialize the display
  334.          bock array. */
  335.       dl->display_blocks = Dynarr_new (struct display_block);
  336.     }
  337.  
  338.   /* The line doesn't have a block of the desired type so go ahead and create
  339.      one and add it to the line. */
  340.   memset (&db, 0, sizeof (struct display_block));
  341.   db.type = type;
  342.   db.runes = Dynarr_new (struct rune);
  343.   Dynarr_add (dl->display_blocks, db);
  344.  
  345.   /* Return the newly added display block. */
  346.   elt = Dynarr_length (dl->display_blocks) - 1;
  347.  
  348.   return Dynarr_atp (dl->display_blocks, elt);
  349. }
  350.  
  351. static int
  352. tab_char_width (struct window *w)
  353. {
  354.   struct buffer *b = XBUFFER (w->buffer);
  355.   int char_tab_width = XINT (b->tab_width);
  356.  
  357.   if (char_tab_width <= 0 || char_tab_width > 1000) char_tab_width = 8;
  358.  
  359.   return char_tab_width;
  360. }
  361.  
  362. static int
  363. space_width (struct window *w)
  364. {
  365.   struct frame *f = XFRAME (w->frame);
  366.   struct device *d = XDEVICE (f->device);
  367.   struct font_metric_info fm;
  368.  
  369.   /* While tabs are traditional composed of spaces, for variable-width
  370.      fonts the space character tends to give too narrow a value.  So
  371.      we use 'n' instead.  Except that we don't.  We use the default
  372.      character width for the default face.  If this is actually
  373.      defined by the font then it is probably the best thing to
  374.      actually use.  If it isn't, we have assumed it is 'n' and have
  375.      already calculated its width.  Thus we can avoid a call to
  376.      XTextWidth on X frames by just querying the default width. */
  377.   DEVMETH (d, font_metric_info, (d, FACE_CACHE_ELEMENT_FONT (w, DEFAULT_INDEX),
  378.                  &fm));
  379.   return fm.width;
  380. }
  381.  
  382. static int
  383. tab_pix_width (struct window *w)
  384. {
  385.   return (space_width (w) * tab_char_width (w));
  386. }
  387.  
  388. /*****************************************************************************
  389.  next_tab_position
  390.  
  391.  Given a pixel position in a window, return the pixel location of the next
  392.  tabstop.  Tabs are calculated from the left window edge in terms of spaces
  393.  displayed in the default face.  Formerly the space width was determined
  394.  using the currently active face.  That method leads to tabstops which do not
  395.  line up.
  396.  ****************************************************************************/
  397. static int
  398. next_tab_position (struct window *w, int start_pixpos, int left_pixpos)
  399. {
  400.   int n_pos = left_pixpos;
  401.   int pix_tab_width = tab_pix_width (w);
  402.  
  403.   /* Adjust n_pos for any hscrolling which has happened. */
  404.   if (w->hscroll > 1)
  405.     n_pos -= space_width (w) * (w->hscroll - 1);
  406.  
  407.   while (n_pos <= start_pixpos)
  408.     n_pos += pix_tab_width;
  409.  
  410.   return n_pos;
  411. }
  412.  
  413. /*****************************************************************************
  414.  calculate_display_line_boundaries
  415.  
  416.  For the given window, calculate the outside and margin boundaries for a
  417.  display line.  The whitespace boundaries must be calculated by the text
  418.  layout routines.
  419.  ****************************************************************************/
  420. layout_bounds
  421. calculate_display_line_boundaries (struct window *w, int modeline)
  422. {
  423.   layout_bounds bounds;
  424.  
  425.   /* Set the outermost boundaries which are the boundaries of the
  426.      window itself minus the gutters (and minus the scrollbars if this
  427.      is for the modeline). */
  428.   if (!modeline)
  429.     {
  430.       bounds.left_out = WINDOW_TEXT_LEFT (w);
  431.       bounds.right_out = WINDOW_TEXT_RIGHT (w);
  432.     }
  433.   else
  434.     {
  435.       bounds.left_out = WINDOW_MODELINE_LEFT (w);
  436.       bounds.right_out = WINDOW_MODELINE_RIGHT (w);
  437.     }
  438.  
  439.   /* The inner boundaries mark where the glyph margins are located. */
  440.   bounds.left_in = bounds.left_out + window_left_margin_width (w);
  441.   bounds.right_in = bounds.right_out - window_right_margin_width (w);
  442.  
  443.   /* We cannot fully calculate the whitespace boundaries as they
  444.      depend on the contents of the line being displayed. */
  445.   bounds.left_white = bounds.left_in;
  446.   bounds.right_white = bounds.right_in;
  447.  
  448.   return bounds;
  449. }
  450.  
  451. /*****************************************************************************
  452.  generate_display_line
  453.  
  454.  Given a display line and a starting position, ensure that the contents of
  455.  the display line accurately represent the visual representation of the
  456.  buffer contents starting from the given position when displayed in the given
  457.  window.  The display line ends when the contents of the line reach the right
  458.  boundary of the given window.
  459.  ****************************************************************************/
  460. static Bufpos
  461. generate_display_line (struct window *w, struct display_line *dl, int bounds,
  462.                Bufpos start_pos, int start_col,
  463.                prop_block_dynarr **prop, int type)
  464. {
  465.   Bufpos ret_bufpos;
  466.   int overlay_width;
  467.  
  468.   /* If our caller hasn't already set the boundaries, then do so now. */
  469.   if (!bounds)
  470.     dl->bounds = calculate_display_line_boundaries (w, 0);
  471.  
  472.   /* Reset what this line is using. */
  473.   if (dl->display_blocks)
  474.     Dynarr_reset (dl->display_blocks);
  475.   if (dl->left_glyphs)
  476.     {
  477.       Dynarr_free (dl->left_glyphs);
  478.       dl->left_glyphs = 0;
  479.     }
  480.   if (dl->right_glyphs)
  481.     {
  482.       Dynarr_free (dl->right_glyphs);
  483.       dl->right_glyphs = 0;
  484.     }
  485.  
  486.   /* We aren't generating a modeline at the moment. */
  487.   dl->modeline = 0;
  488.  
  489.   /* Create a display block for the text region of the line. */
  490.   ret_bufpos = create_text_block (w, dl, start_pos, start_col, prop, type);
  491.   dl->bufpos = start_pos;
  492.   if (dl->end_bufpos < dl->bufpos)
  493.     dl->end_bufpos = dl->bufpos;
  494.  
  495.   if (MARKERP (Voverlay_arrow_position)
  496.       && EQ (w->buffer, Fmarker_buffer (Voverlay_arrow_position))
  497.       && start_pos == marker_position (Voverlay_arrow_position)
  498.       && (STRINGP (Voverlay_arrow_string)
  499.       || GLYPHP (Voverlay_arrow_string)))
  500.     {
  501.       overlay_width = create_overlay_glyph_block (w, dl);
  502.     }
  503.   else
  504.     overlay_width = 0;
  505.  
  506.   /* If there are left glyphs associated with any character in the
  507.      text block, then create a display block to handle them. */
  508.   if (dl->left_glyphs != NULL && Dynarr_length (dl->left_glyphs))
  509.     create_left_glyph_block (w, dl, overlay_width);
  510.  
  511.   /* If there are right glyphs associated with any character in the
  512.      text block, then create a display block to handle them. */
  513.   if (dl->right_glyphs != NULL && Dynarr_length (dl->right_glyphs))
  514.     create_right_glyph_block (w, dl);
  515.  
  516.   /* In the future additional types of display blocks may be generated
  517.      here. */
  518.  
  519.   return ret_bufpos;
  520. }
  521.  
  522. /*****************************************************************************
  523.  generate_modeline
  524.  
  525.  Ensure that the given display line DL accurately represents the modeline for
  526.  the given window.
  527.  ****************************************************************************/
  528. static void
  529. generate_modeline (struct window *w, struct display_line *dl, int type)
  530. {
  531.   struct buffer *b = XBUFFER (w->buffer);
  532.   struct frame *f = XFRAME (w->frame);
  533.   struct device *d = XDEVICE (f->device);
  534.  
  535.   /* Unlike display line and rune pointers, this one can't change underneath
  536.      our feet. */
  537.   struct display_block *db = get_display_block_from_line (dl, TEXT);
  538.   struct font_metric_info fm;
  539.   int c_pixpos, max_pixpos, min_pixpos;
  540.  
  541.   /* This will actually determine incorrect inside boundaries for the
  542.      modeline since it ignores the margins.  However being aware of this fact
  543.      we never use those values anywhere so it doesn't matter. */
  544.   dl->bounds = calculate_display_line_boundaries (w, 1);
  545.  
  546.   /* We are generating a modeline. */
  547.   dl->modeline = 1;
  548.   dl->cursor_elt = -1;
  549.  
  550.   /* Reset the runes on the modeline. */
  551.   Dynarr_reset (db->runes);
  552.  
  553.   if (!WINDOW_HAS_MODELINE_P (w))
  554.     {
  555.       struct rune rb;
  556.  
  557.       /* If there is a horizontal scrollbar, don't add anything. */
  558.       if (window_scrollbar_height (w))
  559.     return;
  560.  
  561.       dl->ascent = DEVMETH (d, divider_height, ());
  562.       dl->descent = 0;
  563.       /* The modeline is at the bottom of the gutters. */
  564.       dl->ypos = WINDOW_BOTTOM (w);
  565.  
  566.       rb.findex = MODELINE_INDEX;
  567.       rb.extent = Qnil;
  568.       rb.xpos = dl->bounds.left_out;
  569.       rb.width = dl->bounds.right_out - dl->bounds.left_out;
  570.       rb.bufpos = 0;
  571.       rb.endpos = 0;
  572.       rb.type = HLINE;
  573.       rb.object.hline.thickness = 1;
  574.       rb.object.hline.yoffset = 0;
  575.       rb.cursor_type = NO_CURSOR;
  576.  
  577.       if (!EQ (Qzero, w->modeline_shadow_thickness)
  578.       && FRAME_IS_WIN (f))
  579.     {
  580.       int shadow_thickness = MODELINE_SHADOW_THICKNESS (w);
  581.  
  582.       dl->ypos -= shadow_thickness;
  583.       rb.xpos += shadow_thickness;
  584.       rb.width -= 2 * shadow_thickness;
  585.     }
  586.  
  587.       Dynarr_add (db->runes, rb);
  588.       return;
  589.     }
  590.  
  591.   DEVMETH (d, font_metric_info, (d, FACE_CACHE_ELEMENT_FONT (w, MODELINE_INDEX),
  592.                  &fm));
  593.  
  594.   dl->ascent = fm.ascent;
  595.   dl->descent = fm.descent;
  596.   /* The modeline is at the bottom of the gutters. */
  597.   dl->ypos = WINDOW_BOTTOM (w) - dl->descent;
  598.  
  599.   c_pixpos = dl->bounds.left_out;
  600.   min_pixpos = dl->bounds.left_out;
  601.   max_pixpos = dl->bounds.right_out;
  602.  
  603.   if (!EQ (Qzero, w->modeline_shadow_thickness) && FRAME_IS_WIN (f))
  604.     {
  605.       int shadow_thickness = MODELINE_SHADOW_THICKNESS (w);
  606.  
  607.       dl->ypos -= shadow_thickness;
  608.       c_pixpos += shadow_thickness;
  609.       min_pixpos += shadow_thickness;
  610.       max_pixpos -= shadow_thickness;
  611.     }
  612.  
  613.   /* This recursively builds up the modeline. */
  614.   Dynarr_reset (mode_string_buffer);
  615.   generate_modeline_string (w, 0, 0, -1, b->modeline_format, 0,
  616.                 max_pixpos - min_pixpos, MODELINE_INDEX, type);
  617.  
  618.   if (Dynarr_length (mode_string_buffer))
  619.     {
  620.       pos_data data;
  621.  
  622.       memset (&data, 0, sizeof (pos_data));
  623.       data.d = d;
  624.       data.db = db;
  625.       data.dl = dl;
  626.       data.findex = MODELINE_INDEX;
  627.       data.pixpos = min_pixpos;
  628.       data.max_pixpos = max_pixpos;
  629.       data.bufpos = 0;
  630.       data.endpos = 0;
  631.       data.width = 0;
  632.       data.cursor_type = NO_CURSOR;
  633.       data.start_col = data.start_col_enabled = 0;
  634.       XSETWINDOW (data.window, w);
  635.  
  636.       add_string_of_emchar_runes (&data, Dynarr_atp (mode_string_buffer, 0),
  637.                   Dynarr_length (mode_string_buffer));
  638.  
  639.       if (Dynarr_length (db->runes))
  640.     {
  641.       struct rune *rb =
  642.         Dynarr_atp (db->runes, Dynarr_length (db->runes) - 1);
  643.       c_pixpos = rb->xpos + rb->width;
  644.     }
  645.       else
  646.     c_pixpos = min_pixpos;
  647.  
  648.       /* If we don't reach the right side of the window, add a blank
  649.      rune to make up the difference.  This usually only occurs if
  650.      the modeline face is using a proportional width font or a
  651.      fixed width font of a different size from the default face
  652.      font. */
  653.  
  654.       if (c_pixpos < max_pixpos)
  655.     {
  656.       data.pixpos = c_pixpos;
  657.       data.width = max_pixpos - data.pixpos;
  658.  
  659.       add_blank_rune (&data, NULL, 0);
  660.     }
  661.     }
  662. }
  663.  
  664. static int
  665. add_string_to_mode_string_buffer (Bufbyte *str, int pos, int min, int max)
  666. {
  667.   int end;
  668.   Bufbyte *cur_pos = str;
  669.   Emchar space = ' ';
  670.  
  671.   while (Dynarr_length (mode_string_buffer) < pos)
  672.     Dynarr_add (mode_string_buffer, ' ');
  673.  
  674.   end = Dynarr_length (mode_string_buffer) + strlen ((char *) str);
  675.   if (max != -1)
  676.     end = min (max, end);
  677.  
  678.   while (pos < end && *cur_pos)
  679.     {
  680.       Emchar ch = charptr_to_emchar (cur_pos);
  681.       Dynarr_add (mode_string_buffer, ch);
  682.       INC_CHARPTR (cur_pos);
  683.       pos++;
  684.     }
  685.  
  686.   while (Dynarr_length (mode_string_buffer) < min)
  687.     Dynarr_add (mode_string_buffer, space);
  688.  
  689.   return Dynarr_length (mode_string_buffer);
  690. }
  691.  
  692. /* If max_pos is == -1, it is considered to be infinite.  The same is
  693.    true of max_pixsize. */
  694.  
  695. #define SET_CURRENT_MODE_STRING_PIXSIZE        \
  696.  cur_pixsize = DEVMETH (d, text_width,        \
  697.             (w, FACE_CACHE_ELEMENT_FONT (w, findex), \
  698.              Dynarr_atp (mode_string_buffer, 0), \
  699.              Dynarr_length (mode_string_buffer)))
  700.  
  701. int
  702. generate_modeline_string (struct window *w, int pos, int min_pos, int max_pos,
  703.               Lisp_Object elt, int depth, int max_pixsize,
  704.               face_index findex, int type)
  705. {
  706.   struct device *d = XDEVICE (XFRAME (w->frame)->device);
  707.  
  708.   /* #### Having to set the current buffer sucks.  Do it for now, but
  709.      later extend the necessary internal routines of stuff such as
  710.      Fsymbol_value to take a buffer argument. */
  711.   struct buffer *old_buffer = current_buffer;
  712.   current_buffer = XBUFFER (w->buffer);
  713.  
  714. tail_recurse:
  715.   if (depth > 10)
  716.     goto invalid;
  717.  
  718.   depth++;
  719.  
  720.   if (STRINGP (elt))
  721.     {
  722.       /* A string.  Add to the display line and check for %-constructs
  723.          within it. */
  724.  
  725.       Bufbyte *this = string_data (XSTRING (elt));
  726.  
  727.       while ((pos < max_pos || max_pos == -1) && *this)
  728.     {
  729.       Bufbyte *last = this;
  730.  
  731.       while (*this && *this != '%')
  732.         this++;
  733.  
  734.       if (this != last)
  735.         {
  736.           /* The string is just a string. */
  737.           int size = this - last + pos;
  738.           int tmp_max = (max_pos == -1 ? size : min (size, max_pos));
  739.  
  740.           pos = add_string_to_mode_string_buffer (last, pos, pos, tmp_max);
  741.         }
  742.       else /* *this == '%' */
  743.         {
  744.           int spec_width = 0;
  745.  
  746.           this++; /* skip over '%' */
  747.  
  748.               /* We can't allow -ve args due to the "%-" construct.
  749.                * Argument specifies minwidth but not maxwidth
  750.                * (maxwidth can be specified by
  751.                * (<negative-number> . <stuff>) modeline elements)
  752.                */
  753.           while (isdigit (*this))
  754.                 {
  755.                   spec_width = spec_width * 10 + (*this - '0');
  756.           this++;
  757.                 }
  758.           spec_width += pos;
  759.  
  760.           if (*this == 'M')
  761.         {
  762.           pos = generate_modeline_string (w, pos, spec_width, max_pos,
  763.                           Vglobal_mode_string, depth,
  764.                           max_pixsize, findex, type);
  765.         }
  766.           else if (*this == '-')
  767.         {
  768.           int num_to_add;
  769.  
  770.           if (max_pixsize < 0)
  771.             num_to_add = 0;
  772.           else if (max_pos != -1)
  773.             num_to_add = max_pos - pos;
  774.           else
  775.             {
  776.               int cur_pixsize;
  777.               int dash_pixsize;
  778.               Emchar ch = '-';
  779.               SET_CURRENT_MODE_STRING_PIXSIZE;
  780.  
  781.               dash_pixsize =
  782.             DEVMETH (d, text_width,
  783.                  (w, FACE_CACHE_ELEMENT_FONT (w, findex), &ch,
  784.                   1));
  785.  
  786.               num_to_add = (max_pixsize - cur_pixsize) / dash_pixsize;
  787.               num_to_add++;
  788.             }
  789.  
  790.           while (num_to_add--)
  791.             pos = add_string_to_mode_string_buffer ((Bufbyte *) "-",
  792.                                 pos, pos, max_pos);
  793.         }
  794.           else if (*this != 0)
  795.         {
  796.           Bufbyte *str;
  797.           Emchar ch = charptr_to_emchar (this);
  798.           decode_mode_spec (w, ch, type);
  799.  
  800.           str = Dynarr_atp (mode_spec, 0);
  801.           pos = add_string_to_mode_string_buffer (str, pos, pos,
  802.                               max_pos);
  803.         }
  804.  
  805.           /* NOT this++.  There could be any sort of character at
  806.          the current position. */
  807.           INC_CHARPTR (this);
  808.         }
  809.  
  810.       if (max_pixsize > 0)
  811.         {
  812.           int cur_pixsize;
  813.           SET_CURRENT_MODE_STRING_PIXSIZE;
  814.  
  815.           if (cur_pixsize >= max_pixsize)
  816.         break;
  817.         }
  818.     }
  819.     }
  820.   else if (SYMBOLP (elt))
  821.     {
  822.       /* A symbol: process the value of the symbol recursively
  823.      as if it appeared here directly.  Avoid error if symbol void.
  824.      Special case: if value of symbol is a string, output the string
  825.      literally.  */
  826.       Lisp_Object tem = Fboundp (elt);
  827.  
  828.       if (!NILP (tem))
  829.     {
  830.       tem = Fsymbol_value (elt);
  831.  
  832.           /* If value is a string, output that string literally:
  833.              don't check for % within it.  */
  834.           if (STRINGP (tem))
  835.             {
  836.           pos =
  837.         add_string_to_mode_string_buffer (string_data (XSTRING (tem)),
  838.                           pos, min_pos, max_pos);
  839.             }
  840.           /* Give up right away for nil or t.  */
  841.           else if (!EQ (tem, elt))
  842.         {
  843.           elt = tem; 
  844.           goto tail_recurse; 
  845.         }
  846.         }
  847.     }
  848.   else if (CONSP (elt))
  849.     {
  850.       /* A cons cell: three distinct cases.
  851.        * If first element is a string or a cons, process all the elements
  852.        * and effectively concatenate them.
  853.        * If first element is a negative number, truncate displaying cdr to
  854.        * at most that many characters.  If positive, pad (with spaces)
  855.        * to at least that many characters.
  856.        * If first element is a symbol, process the cadr or caddr recursively
  857.        * according to whether the symbol's value is non-nil or nil.
  858.        */
  859.       Lisp_Object car, tem;
  860.  
  861.       car = XCAR (elt);
  862.       if (SYMBOLP (car))
  863.         {
  864.           tem = Fboundp (car);
  865.           elt = XCDR (elt);
  866.           if (!CONSP (elt))
  867.             goto invalid;
  868.           /* elt is now the cdr, and we know it is a cons cell.
  869.              Use its car if CAR has a non-nil value.  */
  870.           if (!NILP (tem))
  871.             {
  872.               tem = Fsymbol_value (car);
  873.               if (!NILP (tem))
  874.                 {
  875.                   elt = XCAR (elt); 
  876.                   goto tail_recurse;
  877.         }
  878.             }
  879.           /* Symbol's value is nil (or symbol is unbound)
  880.            * Get the cddr of the original list
  881.            * and if possible find the caddr and use that.
  882.            */
  883.           elt = XCDR (elt);
  884.           if (NILP (elt))
  885.             ;
  886.           else if (!CONSP (elt))
  887.             goto invalid;
  888.           else
  889.             {
  890.               elt = XCAR (elt);
  891.               goto tail_recurse;
  892.             }
  893.         }
  894.       else if (INTP (car))
  895.         {
  896.           int lim = XINT (car);
  897.  
  898.           elt = XCDR (elt);
  899.  
  900.           if (lim < 0)
  901.         {
  902.           /* Negative int means reduce maximum width.
  903.            * DO NOT change MIN_PIXPOS here!
  904.            * (20 -10 . foo) should truncate foo to 10 col
  905.            * and then pad to 20.
  906.            */
  907.           if (max_pos == -1)
  908.         max_pos = pos - lim;
  909.           else
  910.         max_pos = min (max_pos, pos - lim);
  911.         }
  912.           else if (lim > 0)
  913.             {
  914.               /* Padding specified.  Don't let it be more than
  915.                * current maximum.
  916.                */
  917.               lim += pos;
  918.               if (max_pos != -1 && lim > max_pos)
  919.                 lim = max_pos;
  920.               /* If that's more padding than already wanted, queue it.
  921.                * But don't reduce padding already specified even if
  922.                * that is beyond the current truncation point.
  923.                */
  924.               if (lim > min_pos)
  925.                 min_pos = lim;
  926.             }
  927.           goto tail_recurse;
  928.         }
  929.       else if (STRINGP (car) || CONSP (car))
  930.         {
  931.           int limit = 50;
  932.           /* LIMIT is to protect against circular lists.  */
  933.           while (CONSP (elt) && --limit > 0
  934.                  && (pos < max_pos || max_pos == -1))
  935.             {
  936.           pos = generate_modeline_string (w, pos, pos, max_pos, XCAR (elt),
  937.                           depth, max_pixsize, findex,
  938.                           type);
  939.               elt = XCDR (elt);
  940.             }
  941.         }
  942.     }
  943.   else
  944.     {
  945.     invalid:
  946.       pos =
  947.     add_string_to_mode_string_buffer ((Bufbyte *) GETTEXT ("*invalid*"),
  948.                       pos, min_pos, max_pos);
  949.     }
  950.  
  951.   if (min_pos > pos)
  952.     {
  953.       add_string_to_mode_string_buffer ((Bufbyte *) "", pos, min_pos, -1);
  954.     }
  955.  
  956.   current_buffer = old_buffer;
  957.   return pos;
  958. }
  959.  
  960. /*****************************************************************************
  961.  add_hscroll_rune
  962.  
  963.  Adds an hscroll glyph to a display block.  If this is called, then the
  964.  block had better be empty.
  965.  
  966.  Yes, there are multiple places where this function is called but that
  967.  is the way it has to be.  Each calling function has to deal with
  968.  start_col_enabled a little differently depending on the object being
  969.  worked with.
  970.  ****************************************************************************/
  971. static prop_block_dynarr *
  972. add_hscroll_rune (pos_data *data)
  973. {
  974.   struct glyph_block gb;
  975.   prop_block_dynarr *retval;
  976.   Bufpos old_cursor_bufpos = data->cursor_bufpos;
  977.   enum cursor_type old_cursor_type = data->cursor_type;
  978.   Bufpos old_bufpos = data->bufpos;
  979.  
  980.   if (data->cursor_type == CURSOR_ON
  981.       && data->cursor_bufpos >= data->start_col_enabled
  982.       && data->cursor_bufpos <= data->bufpos)
  983.     {
  984.       data->cursor_bufpos = data->start_col_enabled;
  985.     }
  986.   else
  987.     {
  988.       data->cursor_type = NO_CURSOR;
  989.     }
  990.  
  991.   data->endpos = data->bufpos;
  992.   data->bufpos = data->start_col_enabled;
  993.  
  994.   gb.extent = Qnil;
  995.   gb.glyph = Vhscroll_glyph;
  996.   retval = add_glyph_rune (data, &gb, BEGIN_GLYPHS, 1,
  997.                GLYPH_CACHE_ELEMENT (XWINDOW (data->window),
  998.                         HSCROLL_GLYPH_INDEX));
  999.  
  1000.   data->endpos = 0;
  1001.   data->cursor_bufpos = old_cursor_bufpos;
  1002.   data->cursor_type = old_cursor_type;
  1003.   data->bufpos = old_bufpos;
  1004.  
  1005.   data->start_col_enabled = 0;
  1006.   return retval;
  1007. }
  1008.  
  1009. /*****************************************************************************
  1010.  add_emchar_rune
  1011.  
  1012.  Adds a character rune to a display block.  If there is not enough room to
  1013.  fit the rune on the display block (as determined by the MAX_PIXPOS) then
  1014.  it adds nothing and returns ADD_FAILED.
  1015.  ****************************************************************************/
  1016. static prop_block_dynarr *
  1017. add_emchar_rune (pos_data *data)
  1018. {
  1019.   struct rune rb, *crb;
  1020.   int width, local;
  1021.  
  1022.   if (data->start_col)
  1023.     {
  1024.       data->start_col--;
  1025.  
  1026.       if (data->start_col)
  1027.     return NULL;
  1028.     }
  1029.  
  1030.   if (data->start_col_enabled)
  1031.     {
  1032.       return add_hscroll_rune (data);
  1033.     }
  1034.  
  1035.   if (data->width)
  1036.     width = data->width;
  1037.   else
  1038.     {
  1039.       struct window *w = XWINDOW (data->window);
  1040.       width = 
  1041.     DEVMETH (data->d, text_width, (w,
  1042.                        FACE_CACHE_ELEMENT_FONT (w, data->findex),
  1043.                        &data->ch, 1));
  1044.     }
  1045.  
  1046.   if (data->pixpos + width > data->max_pixpos)
  1047.     {
  1048.       return ADD_FAILED;
  1049.     }
  1050.  
  1051.   if (Dynarr_length (data->db->runes) < Dynarr_largest (data->db->runes))
  1052.     {
  1053.       crb = Dynarr_atp (data->db->runes, Dynarr_length (data->db->runes));
  1054.       local = 0;
  1055.     }
  1056.   else
  1057.     {
  1058.       crb = &rb;
  1059.       local = 1;
  1060.     }
  1061.  
  1062.   crb->findex = data->findex;
  1063.   crb->extent = Qnil;        /* only care about extent with glyphs */
  1064.   crb->xpos = data->pixpos;
  1065.   crb->width = width;
  1066.   crb->bufpos = data->bufpos;
  1067.   crb->type = CHAR;
  1068.   crb->object.ch = data->ch;
  1069.   crb->endpos = 0;
  1070.  
  1071.   if (data->cursor_type == CURSOR_ON)
  1072.     {
  1073.       if (data->bufpos == data->cursor_bufpos)
  1074.     {
  1075.       crb->cursor_type = CURSOR_ON;
  1076.       data->cursor_x = Dynarr_length (data->db->runes);
  1077.     }
  1078.       else
  1079.     crb->cursor_type = CURSOR_OFF;
  1080.     }
  1081.   else if (data->cursor_type == NEXT_CURSOR)
  1082.     {
  1083.       crb->cursor_type = CURSOR_ON;
  1084.       data->cursor_x = Dynarr_length (data->db->runes);
  1085.       data->cursor_type = NO_CURSOR;
  1086.     }
  1087.   else if (data->cursor_type == IGNORE_CURSOR)
  1088.     crb->cursor_type = IGNORE_CURSOR;
  1089.   else
  1090.     crb->cursor_type = CURSOR_OFF;
  1091.  
  1092.   if (local)
  1093.     Dynarr_add (data->db->runes, *crb);
  1094.   else
  1095.     Dynarr_increment (data->db->runes);
  1096.  
  1097.   data->pixpos += width;
  1098.  
  1099.   return NULL;
  1100. }
  1101.  
  1102. /*****************************************************************************
  1103.  add_string_of_bufbyte_runes
  1104.  
  1105.  Given a string C_STRING of length C_LENGTH, call add_emchar_rune for
  1106.  each character in the string.  Propagate any left-over data unless
  1107.  NO_PROP is non-zero.
  1108.  ****************************************************************************/
  1109. static prop_block_dynarr *
  1110. add_string_of_bufbyte_runes (pos_data *data, Bufbyte *c_string,
  1111.                  Bytecount c_length, int no_prop)
  1112. {
  1113.   Bufbyte *pos, *end = c_string + c_length;
  1114.   prop_block_dynarr *prop;
  1115.  
  1116.   /* #### This function is too simplistic.  It needs to do the same
  1117.      sort of character interpretation (display-table lookup,
  1118.      ctl-arrow checking), etc. that create_text_block() does.
  1119.      The functionality to do this in that routine needs to be
  1120.      modularized. */
  1121.      
  1122.   for (pos = c_string; pos < end;)
  1123.     {
  1124.       data->ch = charptr_to_emchar (pos);
  1125.  
  1126.       prop = add_emchar_rune (data);
  1127.  
  1128.       if (prop)
  1129.     {
  1130.       if (no_prop)
  1131.         return ADD_FAILED;
  1132.       else
  1133.         {
  1134.           struct prop_block pb;
  1135.           Bytecount len = end - pos;
  1136.           prop = Dynarr_new (struct prop_block);
  1137.  
  1138.           pb.type = PROP_STRING;
  1139.           pb.data.p_string.str =
  1140.         (Bufbyte *) xmalloc (sizeof (Bufbyte) * len);
  1141.           strncpy ((char *) pb.data.p_string.str, (char *) pos, len);
  1142.           pb.data.p_string.len = len;
  1143.  
  1144.           Dynarr_add (prop, pb);
  1145.           return prop;
  1146.         }
  1147.     }
  1148.       INC_CHARPTR (pos);
  1149.       assert (pos <= end);
  1150.     }
  1151.  
  1152.   return NULL;
  1153. }
  1154.  
  1155. /*****************************************************************************
  1156.  add_string_of_emchar_runes
  1157.  
  1158.  Given a string E_STRING of length E_LENGTH, call add_emchar_rune for
  1159.  each character in the string.  Doesn't propogate any data.  This is
  1160.  currently only used by generate_modeline_string.
  1161.  ****************************************************************************/
  1162. static prop_block_dynarr *
  1163. add_string_of_emchar_runes (pos_data *data, Emchar *e_string,
  1164.                 Bytecount e_length)
  1165. {
  1166.   Emchar *pos, *end = e_string + e_length;
  1167.   prop_block_dynarr *prop;
  1168.  
  1169.   for (pos = e_string; pos < end;)
  1170.     {
  1171.       data->ch = *pos;
  1172.       prop = add_emchar_rune (data);
  1173.  
  1174.       if (prop)
  1175.     return ADD_FAILED;
  1176.  
  1177.       INC_CHARPTR (pos);
  1178.       assert (pos <= end);
  1179.     }
  1180.  
  1181.   return NULL;
  1182. }
  1183.  
  1184. /*****************************************************************************
  1185.  add_blank_rune
  1186.  
  1187.  Add a single rune of the specified width.  The area covered by this
  1188.  rune will be displayed in the foreground color of the associated
  1189.  face.
  1190.  ****************************************************************************/
  1191. static prop_block_dynarr *
  1192. add_blank_rune (pos_data *data, struct window *w, int char_tab_width)
  1193. {
  1194.   struct rune rb;
  1195.  
  1196.   /* If data->start_col is not 0 then this call to add_blank_rune must have
  1197.      be to add it as a tab. */
  1198.   if (data->start_col)
  1199.     {
  1200.       /* assert (w != NULL) */
  1201.       prop_block_dynarr *retval;
  1202.  
  1203.       /* If we have still not fully scrolled horizontally, subtract
  1204.          the width of this tab and return. */
  1205.       if (char_tab_width < data->start_col)
  1206.     {
  1207.       data->start_col -= char_tab_width;
  1208.       return NULL;
  1209.     }
  1210.       else if (char_tab_width == data->start_col)
  1211.     data->width = 0;
  1212.       else
  1213.     {
  1214.       int spcwid = space_width (w);
  1215.  
  1216.       if (spcwid >= data->width)
  1217.         data->width = 0;
  1218.       else
  1219.         data->width -= spcwid;
  1220.     }
  1221.       
  1222.       data->start_col = 0;
  1223.       retval = add_hscroll_rune (data);
  1224.  
  1225.       /* Could be caused by the handling of the hscroll rune. */
  1226.       if (retval != NULL || !data->width)
  1227.     return retval;
  1228.     }
  1229.  
  1230.   /* Blank runes are always calculated to fit. */
  1231.   assert (data->pixpos + data->width <= data->max_pixpos);
  1232.  
  1233.   rb.findex = data->findex;
  1234.   rb.extent = Qnil;        /* only care about extent with glyphs */
  1235.   rb.xpos = data->pixpos;
  1236.   rb.width = data->width;
  1237.   rb.bufpos = data->bufpos;
  1238.   rb.endpos = 0;
  1239.   rb.type = BLANK;
  1240.  
  1241.   if (data->cursor_type == CURSOR_ON)
  1242.     {
  1243.       if (data->bufpos == data->cursor_bufpos)
  1244.     {
  1245.       rb.cursor_type = CURSOR_ON;
  1246.       data->cursor_x = Dynarr_length (data->db->runes);
  1247.     }
  1248.       else
  1249.     rb.cursor_type = CURSOR_OFF;
  1250.     }
  1251.   else if (data->cursor_type == NEXT_CURSOR)
  1252.     {
  1253.       rb.cursor_type = CURSOR_ON;
  1254.       data->cursor_x = Dynarr_length (data->db->runes);
  1255.       data->cursor_type = NO_CURSOR;
  1256.     }
  1257.   else
  1258.     rb.cursor_type = CURSOR_OFF;
  1259.  
  1260.   Dynarr_add (data->db->runes, rb);
  1261.   data->pixpos += data->width;
  1262.  
  1263.   return NULL;
  1264. }
  1265.  
  1266. /*****************************************************************************
  1267.  add_octal_runes
  1268.  
  1269.  Add runes representing a character in octal.
  1270.  ****************************************************************************/
  1271.  
  1272. #define ADD_NEXT_OCTAL_RUNE_CHAR do                \
  1273. {                                \
  1274.   if (add_failed || (add_failed = add_emchar_rune (data)))    \
  1275.     {                                \
  1276.       struct prop_block pb;                    \
  1277.       if (!prop)                        \
  1278.     prop = Dynarr_new (struct prop_block);            \
  1279.                                 \
  1280.       pb.type = PROP_CHAR;                    \
  1281.       pb.data.p_char.ch = data->ch;                \
  1282.       pb.data.p_char.cursor_type = data->cursor_type;        \
  1283.       Dynarr_add (prop, pb);                    \
  1284.     }                                \
  1285. } while (0)
  1286.  
  1287. static prop_block_dynarr *
  1288. add_octal_runes (pos_data *data)
  1289. {
  1290.   prop_block_dynarr *prop, *add_failed;
  1291.   Emchar orig_char = data->ch;
  1292.   enum cursor_type orig_cursor_type = data->cursor_type;
  1293.  
  1294.   /* Initialize */
  1295.   prop = NULL;
  1296.   add_failed = NULL;
  1297.  
  1298.   if (data->start_col)
  1299.     data->start_col--;
  1300.  
  1301.   if (!data->start_col)
  1302.     {
  1303.     if (data->start_col_enabled)
  1304.       {
  1305.     add_failed = add_hscroll_rune (data);
  1306.       }
  1307.     else
  1308.       {
  1309.     struct glyph_block gb;
  1310.     struct window *w = XWINDOW (data->window);
  1311.  
  1312.     gb.extent = Qnil;
  1313.     gb.glyph = Voctal_escape_glyph;
  1314.     add_failed =
  1315.       add_glyph_rune (data, &gb, BEGIN_GLYPHS, 1,
  1316.               GLYPH_CACHE_ELEMENT (w, OCT_ESC_GLYPH_INDEX));
  1317.       }
  1318.     }
  1319.  
  1320.   /* We only propagate information if the glyph was partially
  1321.      added. */
  1322.   if (add_failed)
  1323.     return add_failed;
  1324.  
  1325.   data->cursor_type = IGNORE_CURSOR;
  1326.  
  1327.   if (data->ch >= 0x100)
  1328.     {
  1329.       /* If the character is an extended Mule character, it could have
  1330.      up to 19 bits.  For the moment, we treat it as a seven-digit
  1331.      octal number.  This is not that pretty, but whatever. */
  1332.       data->ch = (7 & (orig_char >> 18)) + '0';
  1333.       ADD_NEXT_OCTAL_RUNE_CHAR;
  1334.  
  1335.       data->ch = (7 & (orig_char >> 15)) + '0';
  1336.       ADD_NEXT_OCTAL_RUNE_CHAR;
  1337.  
  1338.       data->ch = (7 & (orig_char >> 12)) + '0';
  1339.       ADD_NEXT_OCTAL_RUNE_CHAR;
  1340.  
  1341.       data->ch = (7 & (orig_char >> 9)) + '0';
  1342.       ADD_NEXT_OCTAL_RUNE_CHAR;
  1343.     }
  1344.  
  1345.   data->ch = (7 & (orig_char >> 6)) + '0';
  1346.   ADD_NEXT_OCTAL_RUNE_CHAR;
  1347.  
  1348.   data->ch = (7 & (orig_char >> 3)) + '0';
  1349.   ADD_NEXT_OCTAL_RUNE_CHAR;
  1350.  
  1351.   data->ch = (7 & orig_char) + '0';
  1352.   ADD_NEXT_OCTAL_RUNE_CHAR;
  1353.  
  1354.   data->cursor_type = orig_cursor_type;
  1355.   return prop;
  1356. }
  1357.  
  1358. #undef ADD_NEXT_OCTAL_RUNE_CHAR
  1359.  
  1360. /*****************************************************************************
  1361.  add_control_char_runes
  1362.  
  1363.  Add runes representing a control character to a display block.
  1364.  ****************************************************************************/
  1365. static prop_block_dynarr *
  1366. add_control_char_runes (pos_data *data, struct buffer *b)
  1367. {
  1368.   if (!NILP (b->ctl_arrow))
  1369.     {
  1370.       prop_block_dynarr *prop;
  1371.       Emchar orig_char = data->ch;
  1372.       enum cursor_type old_cursor_type = data->cursor_type;
  1373.  
  1374.       /* Initialize */
  1375.       prop = NULL;
  1376.  
  1377.       if (data->start_col)
  1378.     data->start_col--;
  1379.  
  1380.       if (!data->start_col)
  1381.     {
  1382.       if (data->start_col_enabled)
  1383.         {
  1384.           prop_block_dynarr *retval;
  1385.  
  1386.           retval = add_hscroll_rune (data);
  1387.           if (retval)
  1388.         return retval;
  1389.         }
  1390.       else
  1391.         {
  1392.           struct glyph_block gb;
  1393.           struct window *w = XWINDOW (data->window);
  1394.  
  1395.           gb.extent = Qnil;
  1396.           gb.glyph = Vcontrol_arrow_glyph;
  1397.  
  1398.           /* We only propagate information if the glyph was partially
  1399.          added. */
  1400.           if (add_glyph_rune (data, &gb, BEGIN_GLYPHS, 1,
  1401.                   GLYPH_CACHE_ELEMENT (w, CONTROL_GLYPH_INDEX)))
  1402.         return ADD_FAILED;
  1403.         }
  1404.     }
  1405.  
  1406.       if (orig_char == 0177)
  1407.     data->ch = '?';
  1408.       else
  1409.     data->ch = orig_char ^ 0100;
  1410.       data->cursor_type = IGNORE_CURSOR;
  1411.  
  1412.       if (add_emchar_rune (data))
  1413.     {
  1414.       struct prop_block pb;
  1415.       if (!prop)
  1416.         prop = Dynarr_new (struct prop_block);
  1417.  
  1418.       pb.type = PROP_CHAR;
  1419.       pb.data.p_char.ch = data->ch;
  1420.       pb.data.p_char.cursor_type = data->cursor_type;
  1421.       Dynarr_add (prop, pb);
  1422.     }
  1423.  
  1424.       data->cursor_type = old_cursor_type;
  1425.       return prop;
  1426.     }
  1427.   else
  1428.     {
  1429.       return add_octal_runes (data);
  1430.     }
  1431. }
  1432.  
  1433. /*****************************************************************************
  1434.  add_disp_table_entry_runes
  1435.  
  1436.  Given a display table entry, call the appropriate functions to
  1437.  display each element of the entry.
  1438.  ****************************************************************************/
  1439. static prop_block_dynarr *
  1440. add_disp_table_entry_runes (pos_data *data, Lisp_Object entry)
  1441. {
  1442.   prop_block_dynarr *prop = NULL;
  1443.  
  1444.   if (VECTORP (entry))
  1445.     {
  1446.       struct Lisp_Vector *de = XVECTOR (entry);
  1447.       long len = vector_length (de);
  1448.       int elt;
  1449.  
  1450.       for (elt = 0; elt < len; elt++)
  1451.     {
  1452.       if (NILP (de->contents[elt]))
  1453.         continue;
  1454.       else if (STRINGP (de->contents[elt]))
  1455.         {
  1456.           prop =
  1457.         add_string_of_bufbyte_runes
  1458.           (data,
  1459.            string_data (XSTRING (de->contents[elt])),
  1460.            string_length (XSTRING (de->contents[elt])),
  1461.            0);
  1462.         }
  1463.       else if (GLYPHP (de->contents[elt]))
  1464.         {
  1465.           if (data->start_col)
  1466.         data->start_col--;
  1467.  
  1468.           if (!data->start_col && data->start_col_enabled)
  1469.         {
  1470.           prop = add_hscroll_rune (data);
  1471.         }
  1472.           else
  1473.         {
  1474.           struct glyph_block gb;
  1475.  
  1476.           gb.glyph = de->contents[elt];
  1477.           gb.extent = Qnil;
  1478.           prop = add_glyph_rune (data, &gb, BEGIN_GLYPHS, 0, 0);
  1479.         }
  1480.         }
  1481.       else if (INTP (de->contents[elt]))
  1482.         {
  1483.           data->ch = XINT (de->contents[elt]);
  1484.           prop = add_emchar_rune (data);
  1485.         }
  1486.       /* Else blow it off because someone added a bad entry and we
  1487.              don't have any safe way of signaling an error. */
  1488.  
  1489.       /* #### Still need to add any remaining elements to the
  1490.              propagation information. */
  1491.       if (prop)
  1492.         return prop;
  1493.     }
  1494.     }
  1495.   else if (STRINGP (entry))
  1496.     {
  1497.       prop = add_string_of_bufbyte_runes (data,
  1498.                       string_data (XSTRING (entry)),
  1499.                       string_length (XSTRING (entry)),
  1500.                       0);
  1501.     }
  1502.   else if (GLYPHP (entry))
  1503.     {
  1504.       if (data->start_col)
  1505.     data->start_col--;
  1506.  
  1507.       if (!data->start_col && data->start_col_enabled)
  1508.     {
  1509.       prop = add_hscroll_rune (data);
  1510.     }
  1511.       else
  1512.     {
  1513.       struct glyph_block gb;
  1514.  
  1515.       gb.glyph = entry;
  1516.       gb.extent = Qnil;
  1517.       prop = add_glyph_rune (data, &gb, BEGIN_GLYPHS, 0, 0);
  1518.     }
  1519.     }
  1520.   else if (INTP (entry))
  1521.     {
  1522.       data->ch = XINT (entry);
  1523.       prop = add_emchar_rune (data);
  1524.     }
  1525.  
  1526.   /* Else blow it off because someone added a bad entry and we don't
  1527.      have any safe way of signaling an error.  Hey, this comment
  1528.      sounds familiar. */
  1529.   return prop;
  1530. }
  1531.  
  1532. /*****************************************************************************
  1533.  add_propagation_runes
  1534.  
  1535.  Add runes which were propagated from the previous line.
  1536.  ****************************************************************************/
  1537. static prop_block_dynarr *
  1538. add_propagation_runes (prop_block_dynarr **prop, pos_data *data)
  1539. {
  1540.   /* #### Remember to handle start_col parameter of data when the rest of
  1541.      this is finished. */
  1542.   int elt;
  1543.   prop_block_dynarr *add_failed;
  1544.   Bufpos old_cursor_bufpos = data->cursor_bufpos;
  1545.   enum cursor_type old_cursor_type = data->cursor_type;
  1546.  
  1547.   for (elt = 0; elt < Dynarr_length (*prop); elt++)
  1548.     {
  1549.       struct prop_block *pb = Dynarr_atp (*prop, elt);
  1550.  
  1551.       switch (pb->type)
  1552.     {
  1553.     case PROP_CHAR:
  1554.       data->ch = pb->data.p_char.ch;
  1555.       data->cursor_bufpos = pb->data.p_char.cursor_bufpos;
  1556.       data->cursor_type = pb->data.p_char.cursor_type;
  1557.       add_failed = add_emchar_rune (data);
  1558.  
  1559.       if (add_failed)
  1560.         {
  1561.           if (elt == 0)
  1562.         {
  1563.           /* We didn't get anything added.  This is virtually
  1564.                      impossible. (Don't speak too fast -- Dubuque
  1565.              will proceed to produce a long list of "reasonable"
  1566.              cases where this would happen.) */
  1567.           data->cursor_bufpos = old_cursor_bufpos;
  1568.           data->cursor_type = old_cursor_type;
  1569.           return *prop;
  1570.         }
  1571.           else
  1572.         {
  1573.           /* Move the remaing entries to the beginning of the
  1574.              array and return. */
  1575.           int end = Dynarr_length (*prop);
  1576.  
  1577.           Dynarr_reset (*prop);
  1578.           while (elt < end)
  1579.             Dynarr_add (*prop, Dynarr_at (*prop, elt));
  1580.  
  1581.           data->cursor_bufpos = old_cursor_bufpos;
  1582.           data->cursor_type = old_cursor_type;
  1583.           return *prop;
  1584.         }
  1585.         }
  1586.       break;
  1587.     case PROP_STRING:
  1588.       if (pb->data.p_string.str)
  1589.         xfree (pb->data.p_string.str);
  1590.       /* #### bogus bogus -- this doesn't do anything!
  1591.          Should probably call add_string_of_bufbyte_runes(),
  1592.          once that function is fixed. */
  1593.       break;
  1594.     case PROP_MINIBUF_PROMPT:
  1595.       /* #### Hey, Ben!  Does this need to probably be using a
  1596.              stream or some kind of accessor function to get the next
  1597.              character in order to make Mule work? */
  1598.       {
  1599.         face_index old_findex = data->findex;
  1600.         Bufpos old_bufpos = data->bufpos;
  1601.  
  1602.         data->findex = DEFAULT_INDEX;
  1603.         data->bufpos = 0;
  1604.         data->cursor_type = NO_CURSOR;
  1605.  
  1606.         while (pb->data.p_string.pos < pb->data.p_string.len)
  1607.           {
  1608.         data->ch = pb->data.p_string.str[pb->data.p_string.pos];
  1609.         add_failed = add_emchar_rune (data);
  1610.  
  1611.         if (add_failed)
  1612.           {
  1613.             data->findex = old_findex;
  1614.             data->bufpos = old_bufpos;
  1615.             data->cursor_bufpos = old_cursor_bufpos;
  1616.             data->cursor_type = old_cursor_type;
  1617.             return *prop;
  1618.           }
  1619.         else
  1620.           pb->data.p_string.pos++;
  1621.           }
  1622.  
  1623.         data->findex = old_findex;
  1624.         /* ##### FIXME FIXME FIXME -- Upon successful return from
  1625.            this function, data->bufpos is automatically incremented.
  1626.            However, we don't want that to happen if we were adding
  1627.            the minibuffer prompt. */
  1628.         data->bufpos = old_bufpos - 1;
  1629.       }
  1630.       break;
  1631.     case PROP_BLANK:
  1632.       {
  1633.         int old_width = data->width;
  1634.         face_index old_findex = data->findex;
  1635.  
  1636.         data->findex = pb->data.p_blank.findex;
  1637.         data->width = pb->data.p_blank.width;
  1638.         data->cursor_bufpos = 0;
  1639.         data->cursor_type = IGNORE_CURSOR;
  1640.  
  1641.         if (data->pixpos + data->width > data->max_pixpos)
  1642.           data->width = data->max_pixpos - data->pixpos;
  1643.  
  1644.         /* We pass a bogus value of char_tab_width.  It shouldn't
  1645.                matter because unless something is really screwed up
  1646.                this call won't cause that arg to be used. */
  1647.         add_failed = add_blank_rune (data, XWINDOW (data->window), 0);
  1648.  
  1649.         /* This can happen in the case where we have a tab which
  1650.                is wider than the window. */
  1651.         if (data->width != pb->data.p_blank.width)
  1652.           {
  1653.         pb->data.p_blank.width -= data->width;
  1654.         add_failed = ADD_FAILED;
  1655.           }
  1656.  
  1657.         data->findex = old_findex;
  1658.         data->width = old_width;
  1659.  
  1660.         if (add_failed)
  1661.           {
  1662.         data->cursor_bufpos = old_cursor_bufpos;
  1663.         data->cursor_type = old_cursor_type;
  1664.         return *prop;
  1665.           }
  1666.       }
  1667.       break;
  1668.     default:
  1669.       abort ();
  1670.     }
  1671.     }
  1672.  
  1673.   Dynarr_free (*prop);
  1674.   data->cursor_bufpos = old_cursor_bufpos;
  1675.   data->cursor_type = old_cursor_type;
  1676.   return NULL;
  1677. }
  1678.  
  1679. /*****************************************************************************
  1680.  add_glyph_rune
  1681.  
  1682.  Add 'text layout glyphs at position POS_TYPE that are contained to
  1683.  the display block, but add all other types to the appropriate list of
  1684.  the display line.  They will be added later by different routines.
  1685.  ****************************************************************************/
  1686. static prop_block_dynarr *
  1687. add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
  1688.         int allow_cursor, struct glyph_cache_element *inst)
  1689. {
  1690.   struct window *w = XWINDOW (data->window);
  1691.  
  1692.   /* A nil extent indicates a special glyph (ex. truncator) */
  1693.   if (NILP (gb->extent)
  1694.       || (pos_type == BEGIN_GLYPHS &&
  1695.       extent_begin_glyph_layout (XEXTENT (gb->extent)) == GL_TEXT)
  1696.       || (pos_type == END_GLYPHS &&
  1697.       extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_TEXT))
  1698.     {
  1699.       struct rune rb;
  1700.       int width;
  1701.       int xoffset = 0;
  1702.       int ascent, descent;
  1703.       Lisp_Object baseline;
  1704.       Lisp_Object face;
  1705.  
  1706.       if (inst)
  1707.     width = inst->width;
  1708.       else
  1709.     width = glyph_width (gb->glyph, data->findex, 0, data->window);
  1710.  
  1711.       if (!width)
  1712.     return NULL;
  1713.  
  1714.       if (data->start_col)
  1715.     {
  1716.       prop_block_dynarr *retval;
  1717.       int glyph_char_width = width / space_width (w);
  1718.  
  1719.       /* If we still have not fully scrolled horizontally after
  1720.              taking into account the width of the glyph, subtract its
  1721.              width and return. */
  1722.       if (glyph_char_width < data->start_col)
  1723.         {
  1724.           data->start_col -= glyph_char_width;
  1725.           return NULL;
  1726.         }
  1727.       else if (glyph_char_width == data->start_col)
  1728.         width = 0;
  1729.       else
  1730.         {
  1731.           xoffset = space_width (w) * data->start_col;
  1732.           width -= xoffset;
  1733.  
  1734.           /* #### Can this happen? */
  1735.           if (width < 0)
  1736.         width = 0;
  1737.         }
  1738.  
  1739.       data->start_col = 0;
  1740.       retval = add_hscroll_rune (data);
  1741.  
  1742.       /* Could be caused by the handling of the hscroll rune. */
  1743.       if (retval != NULL || !width)
  1744.         return retval;
  1745.     }
  1746.       else
  1747.     xoffset = 0;
  1748.  
  1749.       if (data->pixpos + width > data->max_pixpos)
  1750.     {
  1751.       /* If this is the first object we are attempting to add to
  1752.              the line then we ignore the horizontal_clip threshold.
  1753.              Otherwise we will loop until the bottom of the window
  1754.              continually failing to add this glyph because it is wider
  1755.              than the window.  We could alternatively just completely
  1756.              ignore the glyph and proceed from there but I think that
  1757.              this is a better solution. */
  1758.       if (Dynarr_length (data->db->runes)
  1759.           && data->max_pixpos - data->pixpos < horizontal_clip)
  1760.         return ADD_FAILED;
  1761.       else
  1762.         width = data->max_pixpos - data->pixpos;
  1763.     }
  1764.  
  1765.       if (inst)
  1766.     {
  1767.       ascent = inst->ascent;
  1768.       descent = inst->descent;
  1769.     }
  1770.       else
  1771.     {
  1772.       ascent = glyph_ascent (gb->glyph, data->findex, 0, data->window);
  1773.       descent = glyph_descent (gb->glyph, data->findex, 0, data->window);
  1774.     }
  1775.  
  1776.       baseline = glyph_baseline (gb->glyph, data->window);
  1777.  
  1778.       if (glyph_contrib_p (gb->glyph, data->window))
  1779.     {
  1780.       /* A pixmap that has not had a baseline explicitly set.  Its
  1781.          contribution will be determined later. */
  1782.       if (NILP (baseline))
  1783.         {
  1784.           int height = ascent + descent;
  1785.           data->max_pixmap_height = max (data->max_pixmap_height, height);
  1786.         }
  1787.  
  1788.       /* A string so determine contribution normally. */
  1789.       else if (EQ (baseline, Qt))
  1790.         {
  1791.           data->new_ascent = max (data->new_ascent, ascent);
  1792.           data->new_descent = max (data->new_descent, descent);
  1793.         }
  1794.  
  1795.       /* A pixmap with an explicitly set baseline.  We determine the
  1796.          contribution here. */
  1797.       else if (INTP (baseline))
  1798.         {
  1799.           int height = ascent + descent;
  1800.           int pix_ascent, pix_descent;
  1801.  
  1802.           pix_ascent = height * XINT (baseline) / 100;
  1803.           pix_descent = height - pix_ascent;
  1804.  
  1805.           data->new_ascent = max (data->new_ascent, pix_ascent);
  1806.           data->new_descent = max (data->new_descent, pix_descent);
  1807.         }
  1808.  
  1809.       /* Otherwise something is screwed up. */
  1810.       else
  1811.         abort ();
  1812.     }
  1813.  
  1814.       face = glyph_face (gb->glyph, data->window);
  1815.       if (NILP (face))
  1816.     rb.findex = data->findex;
  1817.       else
  1818.     rb.findex = get_builtin_face_cache_index (w, face);
  1819.  
  1820.       rb.extent = gb->extent;
  1821.       rb.xpos = data->pixpos;
  1822.       rb.width = width;
  1823.       rb.bufpos = 0;            /* glyphs are never "at" anywhere */
  1824.       rb.endpos = data->endpos;
  1825.       rb.type = DGLYPH;
  1826.       /* #### Ben sez: this is way bogus if the glyph is a string.
  1827.      You should not make the output routines have to cope with
  1828.      this.  The string could contain Mule characters, or non-
  1829.      printable characters, or characters to be passed through
  1830.      the display table, or non-character objects (when this gets
  1831.      implemented), etc.  Instead, this routine here should parse
  1832.      the string into a series of runes. */
  1833.       rb.object.dglyph.glyph = gb->glyph;
  1834.       rb.object.dglyph.xoffset = xoffset;
  1835.  
  1836.       if (allow_cursor)
  1837.     {
  1838.       rb.bufpos = data->bufpos;
  1839.  
  1840.       if (data->cursor_type == CURSOR_ON)
  1841.         {
  1842.           if (data->bufpos == data->cursor_bufpos)
  1843.         {
  1844.           rb.cursor_type = CURSOR_ON;
  1845.           data->cursor_x = Dynarr_length (data->db->runes);
  1846.         }
  1847.           else
  1848.         rb.cursor_type = CURSOR_OFF;
  1849.         }
  1850.       else if (data->cursor_type == NEXT_CURSOR)
  1851.         {
  1852.           rb.cursor_type = CURSOR_ON;
  1853.           data->cursor_x = Dynarr_length (data->db->runes);
  1854.           data->cursor_type = NO_CURSOR;
  1855.         }
  1856.       else if (data->cursor_type == IGNORE_CURSOR)
  1857.         rb.cursor_type = IGNORE_CURSOR;
  1858.       else if (data->cursor_type == NO_CURSOR)
  1859.         rb.cursor_type = NO_CURSOR;
  1860.       else
  1861.         rb.cursor_type = CURSOR_OFF;
  1862.     }
  1863.       else
  1864.     rb.cursor_type = CURSOR_OFF;
  1865.  
  1866.       Dynarr_add (data->db->runes, rb);
  1867.       data->pixpos += width;
  1868.  
  1869.       return NULL;
  1870.     }
  1871.   else
  1872.     {
  1873.       if (!NILP (glyph_face (gb->glyph, data->window)))
  1874.     gb->findex =
  1875.       get_builtin_face_cache_index (w, glyph_face (gb->glyph,
  1876.                                data->window));
  1877.       else
  1878.     gb->findex = data->findex;
  1879.  
  1880.       if (pos_type == BEGIN_GLYPHS)
  1881.     {
  1882.       if (!data->dl->left_glyphs)
  1883.         data->dl->left_glyphs = Dynarr_new (struct glyph_block);
  1884.       Dynarr_add (data->dl->left_glyphs, *gb);
  1885.       return NULL;
  1886.     }
  1887.       else if (pos_type == END_GLYPHS)
  1888.     {
  1889.       if (!data->dl->right_glyphs)
  1890.         data->dl->right_glyphs = Dynarr_new (struct glyph_block);
  1891.       Dynarr_add (data->dl->right_glyphs, *gb);
  1892.       return NULL;
  1893.     }
  1894.       else
  1895.     abort ();    /* there are no unknown types */
  1896.     }
  1897.  
  1898.   return NULL;    /* shut up compiler */
  1899. }
  1900.  
  1901. /*****************************************************************************
  1902.  add_glyph_runes
  1903.  
  1904.  Add all glyphs at position POS_TYPE that are contained in the given
  1905.  data.
  1906.  ****************************************************************************/
  1907. static prop_block_dynarr *
  1908. add_glyph_runes (pos_data *data, int pos_type)
  1909. {
  1910.   /* #### This still needs to handle the start_col parameter.  Duh, Chuck,
  1911.      why didn't you just modify add_glyph_rune in the first place? */
  1912.   int elt;
  1913.   glyph_block_dynarr *glyph_arr = (pos_type == BEGIN_GLYPHS
  1914.                    ? data->ef->begin_glyphs
  1915.                    : data->ef->end_glyphs);
  1916.   prop_block_dynarr *prop;
  1917.  
  1918.   for (elt = 0; elt < Dynarr_length (glyph_arr); elt++)
  1919.     {
  1920.       prop = add_glyph_rune (data, Dynarr_atp (glyph_arr, elt), pos_type, 0,
  1921.                  0);
  1922.  
  1923.       if (prop)
  1924.     {
  1925.       /* #### Add some propagation information. */
  1926.       return prop;
  1927.     }
  1928.     }
  1929.  
  1930.   Dynarr_reset (glyph_arr);
  1931.  
  1932.   return NULL;
  1933. }
  1934.  
  1935. /*****************************************************************************
  1936.  create_text_block
  1937.  
  1938.  Given a position for a buffer in a window, ensure that the given
  1939.  display line DL accurately represents the text on a line starting at
  1940.  the given position.
  1941.  ****************************************************************************/
  1942. static Bufpos
  1943. create_text_block (struct window *w, struct display_line *dl, Bufpos start_pos,
  1944.            int start_col, prop_block_dynarr **prop, int type)
  1945. {
  1946.   struct frame *f = XFRAME (w->frame);
  1947.   struct buffer *b = XBUFFER (w->buffer);
  1948.   struct device *d = XDEVICE (f->device);
  1949.  
  1950.   pos_data data;
  1951.   struct Lisp_Vector *dt = 0;
  1952.  
  1953.   /* Don't display anything in the minibuffer if this window is not on
  1954.      a selected frame.  We consider all other windows to be active
  1955.      minibuffers as it simplifies the coding. */
  1956.   int active_minibuffer = (!MINI_WINDOW_P (w) ||
  1957.                (f == device_selected_frame (d)));
  1958.  
  1959.   int truncate_win = window_truncation_on (w);
  1960.   int end_glyph_width;
  1961.  
  1962.   /* If the buffer's value of selective_display is an integer then
  1963.      only lines that start with less than selective_display columns of
  1964.      space will be displayed.  If selective_display is t then all text
  1965.      after a ^M is invisible. */
  1966.   int selective = (INTP (b->selective_display)
  1967.            ? XINT (b->selective_display)
  1968.            : ((!NILP (b->selective_display) ? -1 : 0)));
  1969.  
  1970.   /* The variable ctl-arrow allows the user to specify what characters
  1971.      can actually be displayed and which octal should be used for.
  1972.      #### This variable should probably have some rethought done to
  1973.      it.
  1974.  
  1975.      #### It would also be really nice if you could specify that
  1976.      the characters come out in hex instead of in octal.  Mule
  1977.      does that by adding a ctl-hexa variable similar to ctl-arrow,
  1978.      but that's bogus -- we need a more general solution.  I
  1979.      think you need to extend the concept of display tables
  1980.      into a more general conversion mechanism.  Ideally you
  1981.      could specify a Lisp function that converts characters,
  1982.      but this violates the Second Golden Rule and besides would
  1983.      make things way way way way slow.  An idea I like is to
  1984.      be able to specify multiple display tables instead of just
  1985.      one.  Each display table can specify conversions for some
  1986.      characters and leave others unchanged.  The way the
  1987.      character gets displayed is determined by the first display
  1988.      table with a binding for that character.  This way, you
  1989.      could call a function `enable-hex-display' that adds a
  1990.      pre-defined hex display-table (or maybe computes one if
  1991.      you give weird parameters to the function) and adds it
  1992.      to the list of display tables for the current buffer.
  1993.  
  1994.      Unfortunately there are still problems dealing with Mule
  1995.      characters.  For example, maybe I want to specify that
  1996.      all extended characters (i.e. >= 256) are displayed in hex.
  1997.      It's not reasonable to create a mapping for all possible
  1998.      such characters, because there are about 2^19 of them.
  1999.      One way of dealing with this is to extend the concept
  2000.      of what a display table is.  Currently it's only allowed
  2001.      to be a 256-entry vector.  Instead, it should be something
  2002.      like:
  2003.  
  2004.      a) A 256-entry vector, for backward compatibility
  2005.      b) Some sort of hashtable, mapping characters to values
  2006.      c) A list that specifies a range of values and the
  2007.         mapping to provide for those values.
  2008.  
  2009.      Also, extend the concept of "mapping" to include a
  2010.      printf-like spec.  Then, you could make all extended
  2011.      characters show up as hex with a display table like
  2012.  
  2013.      ((256 . 524288) . "%x")
  2014.  
  2015.      Since more than one display table is possible, you have
  2016.      great flexibility in mapping ranges of characters.
  2017.      */
  2018.   Emchar printable_min = (INTP (b->ctl_arrow)
  2019.               ? XINT (b->ctl_arrow)
  2020.               : ((EQ (b->ctl_arrow, Qt) || EQ (b->ctl_arrow, Qnil))
  2021.                  ? 255 : 160));
  2022.  
  2023.   /* The text display block for this display line. */
  2024.   struct display_block *db = get_display_block_from_line (dl, TEXT);
  2025.  
  2026.   /* The first time through the main loop we need to force the glyph
  2027.      data to be updated. */
  2028.   int initial = 1;
  2029.  
  2030.   /* Apparently the new extent_fragment_update returns an end position
  2031.      equal to the position passed in if there are no more runs to be
  2032.      displayed. */
  2033.   int no_more_frags = 0;
  2034.  
  2035.   dl->used_prop_data = 0;
  2036.   dl->num_chars = 0;
  2037.   data.ef = extent_fragment_new (b, f);
  2038.  
  2039.   /* These values are used by all of the rune addition routines.  We add
  2040.      them to this structure for ease of passing. */
  2041.   data.d = d;
  2042.   XSETWINDOW (data.window, w);
  2043.   data.db = db;
  2044.   data.dl = dl;
  2045.  
  2046.   data.bufpos = start_pos;
  2047.   data.endpos = 0;
  2048.   data.pixpos = dl->bounds.left_in;
  2049.   data.new_ascent = data.new_descent = data.max_pixmap_height = 0;
  2050.   data.ch = '\0';
  2051.  
  2052.   /* Set the right boundary adjusting it to take into account any end
  2053.      glyph.  Save the width of the end glyph for later use. */
  2054.   data.max_pixpos = dl->bounds.right_in;
  2055.   if (truncate_win)
  2056.     end_glyph_width = GLYPH_CACHE_ELEMENT_WIDTH (w, TRUN_GLYPH_INDEX);
  2057.   else
  2058.     end_glyph_width = GLYPH_CACHE_ELEMENT_WIDTH (w, CONT_GLYPH_INDEX);
  2059.   data.max_pixpos -= end_glyph_width;
  2060.  
  2061.   if (cursor_in_echo_area)
  2062.     {
  2063.       if (MINI_WINDOW_P (w) && echo_area_active (f))
  2064.     {
  2065.       data.cursor_bufpos = BUF_ZV (b);
  2066.       data.cursor_type = CURSOR_ON;
  2067.     }
  2068.       else
  2069.     data.cursor_type = NO_CURSOR;
  2070.     }
  2071.   else if (MINI_WINDOW_P (w) && !active_minibuffer)
  2072.     data.cursor_type = NO_CURSOR;
  2073.   else if (w == XWINDOW (FRAME_SELECTED_WINDOW (device_selected_frame (d))))
  2074.     {
  2075.       data.cursor_bufpos = BUF_PT (b);
  2076.       data.cursor_type = CURSOR_ON;
  2077.     }
  2078.   else if (w == XWINDOW (FRAME_SELECTED_WINDOW (f)))
  2079.     {
  2080.       data.cursor_bufpos = marker_position (w->pointm[type]);
  2081.       data.cursor_type = CURSOR_ON;
  2082.     }
  2083.   else
  2084.     data.cursor_type = NO_CURSOR;
  2085.   data.cursor_x = -1;
  2086.  
  2087.   data.start_col = w->hscroll;
  2088.   data.start_col_enabled = (w->hscroll ? start_pos : 0);
  2089.  
  2090.   /* We regenerate the line from the very beginning. */
  2091.   Dynarr_reset (db->runes);
  2092.  
  2093.   /* Why is this less than or equal and not just less than?  If the
  2094.      starting position is already equal to the maximum we can't add
  2095.      anything else, right?  Wrong.  We might still have a newline to
  2096.      add.  A newline can use the room allocated for an end glyph since
  2097.      if we add it we know we aren't going to be adding any end
  2098.      glyph. */
  2099.  
  2100.   /* #### Chuck -- I think this condition should be while (1).
  2101.      Otherwise if (e.g.) there is one begin-glyph and one end-glyph
  2102.      and the begin-glyph ends exactly at the end of the window, the
  2103.      end-glyph and text might not be displayed.  while (1) ensures
  2104.      that the loop terminates only when either (a) there is
  2105.      propagation data or (b) the end-of-line or end-of-buffer is hit.
  2106.  
  2107.      #### Also I think you need to ensure that the operation
  2108.      "add begin glyphs; add end glyphs; add text" is atomic and
  2109.      can't get interrupted in the middle.  If you run off the end
  2110.      of the line during that operation, then you keep accumulating
  2111.      propagation data until you're done.  Otherwise, if the (e.g.)
  2112.      there's a begin glyph at a particular position and attempting
  2113.      to display that glyph results in window-end being hit and
  2114.      propagation data being generated, then the character at that
  2115.      position won't be displayed.
  2116.  
  2117.      #### See also the comment after the end of this loop, below.
  2118.      */
  2119.   while (data.pixpos <= data.max_pixpos
  2120.      && (active_minibuffer || !NILP (Vsynchronize_minibuffers)))
  2121.     {
  2122.       /* #### Currently this loop deals entirely in Bufpos's.
  2123.      It could probably be sped up (for Mule) by also
  2124.      keeping track of the current Bytind, to reduce the
  2125.      number of calls to bufpos_to_bytind(). (Remember,
  2126.      this call is made implicitly every time you call
  2127.      any of the BUF_* functions.  The BI_BUF_* functions
  2128.      deal directly in Bytind's and thus do not need this
  2129.      extra call.) However, I don't want to worry about
  2130.      this right now. */
  2131.  
  2132.       /* #### This check probably should not be necessary. */
  2133.       if (data.bufpos > BUF_ZV (b))
  2134.     {
  2135.       data.bufpos--;
  2136.       goto done;
  2137.     }
  2138.  
  2139.       /* If selective display was an integer and we aren't working on
  2140.          a continuation line then find the next line we are actually
  2141.          supposed to display. */
  2142.       if (selective > 0
  2143.       && (data.bufpos == BUF_BEGV (b)
  2144.           || BUF_FETCH_CHAR (b, data.bufpos - 1) == '\n'))
  2145.     {
  2146.       while (spaces_at_point (b, data.bufpos) >= selective)
  2147.         {
  2148.           data.bufpos = find_next_newline_no_quit (b, data.bufpos, 1);
  2149.           if (data.bufpos >= BUF_ZV (b))
  2150.         {
  2151.           data.bufpos = BUF_ZV (b);
  2152.           goto done;
  2153.         }
  2154.         }
  2155.     }
  2156.  
  2157.       /* Check for face changes. */
  2158.       if (initial || (!no_more_frags &&
  2159.               data.bufpos == bytind_to_bufpos (b, data.ef->end)))
  2160.     {
  2161.       /* Now compute the face and begin/end-glyph information. */
  2162.       data.findex =
  2163.         extent_fragment_update (w, data.ef,
  2164.                     /* Remember that the extent-fragment
  2165.                        routines deal in Bytind's.  This
  2166.                        should perhaps be changed, for
  2167.                        consistency. */
  2168.                     bufpos_to_bytind (b, data.bufpos));
  2169.  
  2170.       DEVMETH (d, font_metric_info,
  2171.            (d, FACE_CACHE_ELEMENT_FONT (w, data.findex), &data.fm));
  2172.  
  2173.       if (data.bufpos == bytind_to_bufpos (b, data.ef->end))
  2174.         no_more_frags = 1;
  2175.  
  2176.       dt = get_display_table (w, data.findex);
  2177.       data.new_ascent = max (data.new_ascent, data.fm.ascent);
  2178.       data.new_descent = max (data.new_descent, data.fm.descent);
  2179.  
  2180.       /* It can be expensive to call the text width routines.  If
  2181.          the font we are currently working with is not
  2182.          proportional, we'll pass along the character width so that
  2183.          the addition subroutines don't need to calculate it. */
  2184.       if (data.fm.proportional)
  2185.         data.width = 0;
  2186.       else
  2187.         data.width = data.fm.width;
  2188.     }
  2189.       initial = 0;
  2190.  
  2191.       /* Determine what is next to be displayed.  We first handle any
  2192.          glyphs returned by glyphs_at_bufpos.  If there are no glyphs to
  2193.          display then we determine what to do based on the character at the
  2194.          current buffer position. */
  2195.  
  2196.       /* If the current position is covered by an invisible extent, do
  2197.          nothing.
  2198.  
  2199.      #### The behavior of begin and end-glyphs at the edge of an
  2200.      invisible extent should be investigated further.  This is
  2201.      fairly low priority though. */
  2202.       if (data.ef->invisible)
  2203.     {
  2204.       if (*prop)
  2205.         Dynarr_free (*prop);
  2206.  
  2207.       /* If point is in an invisible region we place it on the
  2208.              next visible character. */
  2209.       if (data.cursor_type == CURSOR_ON
  2210.           && data.bufpos == data.cursor_bufpos)
  2211.         {
  2212.           data.cursor_type = NEXT_CURSOR;
  2213.         }
  2214.  
  2215.       /* #### What if we we're dealing with a display table? */
  2216.       if (data.start_col)
  2217.         data.start_col--;
  2218.  
  2219.       if (data.bufpos == BUF_ZV (b))
  2220.         goto done;
  2221.       else
  2222.         data.bufpos++;
  2223.     }
  2224.  
  2225.       /* If there is propagation data, then it represents the current
  2226.          buffer position being displayed.  Add them and advance the
  2227.          position counter.  This might also add the minibuffer
  2228.          prompt. */
  2229.       else if (*prop)
  2230.     {
  2231.       dl->used_prop_data = 1;
  2232.       *prop = add_propagation_runes (prop, &data);
  2233.  
  2234.       if (*prop)
  2235.         goto done;    /* gee, a really narrow window */
  2236.       else if (data.bufpos == BUF_ZV (b))
  2237.         goto done;
  2238.       else
  2239.         data.bufpos++;
  2240.     }
  2241.  
  2242.       /* If there are end glyphs, add them to the line.  These are
  2243.      the end glyphs for the previous run of text.  We add them
  2244.      here rather than doing them at the end of handling the
  2245.      previous run so that glyphs at the beginning and end of
  2246.      a line are handled correctly. */
  2247.       else if (Dynarr_length (data.ef->end_glyphs) > 0)
  2248.     {
  2249.       *prop = add_glyph_runes (&data, END_GLYPHS);
  2250.       if (*prop)
  2251.         goto done;
  2252.     }
  2253.  
  2254.       /* If there are begin glyphs, add them to the line. */
  2255.       else if (Dynarr_length (data.ef->begin_glyphs) > 0)
  2256.     {
  2257.       *prop = add_glyph_runes (&data, BEGIN_GLYPHS);
  2258.       if (*prop)
  2259.         goto done;
  2260.     }
  2261.  
  2262.       /* If at end-of-buffer, we've already processed begin and
  2263.      end-glyphs at this point and there's no text to process,
  2264.      so we're done. */
  2265.       else if (data.bufpos == BUF_ZV (b))
  2266.     goto done;
  2267.  
  2268.       else
  2269.     {
  2270.       /* Get the character at the current buffer position. */
  2271.       data.ch = BUF_FETCH_CHAR (b, data.bufpos);
  2272.  
  2273.       /* If there is a display table entry for it, hand it off to
  2274.              add_disp_table_entry_runes and let it worry about it. */
  2275.       if (dt && !NILP (DISP_CHAR_ENTRY (dt, data.ch)))
  2276.         {
  2277.           *prop =
  2278.         add_disp_table_entry_runes (&data,
  2279.                         DISP_CHAR_ENTRY (dt, data.ch));
  2280.  
  2281.           if (*prop)
  2282.         goto done;
  2283.         }
  2284.  
  2285.       /* Check if we have hit a newline character.  If so, add a marker
  2286.              to the line and end this loop. */
  2287.       else if (data.ch == '\n')
  2288.         {
  2289.           /* We aren't going to be adding an end glyph so give its
  2290.                  space back in order to make sure that the cursor can
  2291.                  fit. */
  2292.           data.max_pixpos += end_glyph_width;
  2293.  
  2294.           if (selective > 0
  2295.           && (spaces_at_point (b, data.bufpos + 1) >= selective))
  2296.         {
  2297.           /* We won't be adding a truncation or continuation glyph
  2298.              so give up the room allocated for them. */
  2299.           data.max_pixpos += end_glyph_width;
  2300.  
  2301.           if (!NILP (b->selective_display_ellipses))
  2302.             {
  2303.               struct glyph_block gb;
  2304.  
  2305.               gb.extent = Qnil;
  2306.               gb.glyph = Vinvisible_text_glyph;
  2307.               add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 0,
  2308.                       GLYPH_CACHE_ELEMENT (w, INVIS_GLYPH_INDEX));
  2309.             }
  2310.           else
  2311.             {
  2312.               data.width = DEVMETH (d, eol_cursor_width, ());
  2313.               *prop = add_emchar_rune (&data);
  2314.             }
  2315.  
  2316.           /* We need to set data.bufpos to the start of the
  2317.                      next visible region in order to make this line
  2318.                      appear to contain all of the invisible area.
  2319.                      Otherwise, the line cache won't work
  2320.                      correctly. */
  2321.           data.bufpos++;
  2322.           while (spaces_at_point (b, data.bufpos) >= selective)
  2323.             {
  2324.               data.bufpos = find_next_newline_no_quit (b, data.bufpos,
  2325.                                    1);
  2326.               if (data.bufpos >= BUF_ZV (b))
  2327.             {
  2328.               data.bufpos = BUF_ZV (b);
  2329.               break;
  2330.             }
  2331.             }
  2332.           if (BUF_FETCH_CHAR (b, data.bufpos - 1) == '\n')
  2333.             data.bufpos--;
  2334.         }
  2335.           else
  2336.         {
  2337.           data.width = DEVMETH (d, eol_cursor_width, ());
  2338.           *prop = add_emchar_rune (&data);
  2339.         }
  2340.  
  2341.           goto done;
  2342.         }
  2343.  
  2344.       /* If the current character is ^M, and selective display is
  2345.              enabled, then add the invisible-text-glyph if
  2346.              selective-display-ellipses is set.  In any case, this
  2347.              line is done. */
  2348.       else if (data.ch == (('M' & 037)) && selective == -1)
  2349.         {
  2350.           Bufpos next_bufpos;
  2351.  
  2352.           /* Find the buffer position at the end of the line. */
  2353.           next_bufpos = find_next_newline_no_quit (b, data.bufpos, 1);
  2354.           if (BUF_FETCH_CHAR (b, next_bufpos - 1) == '\n')
  2355.         next_bufpos--;
  2356.  
  2357.           /* If the cursor is somewhere in the elided text make
  2358.                  sure that the cursor gets drawn appropriately. */
  2359.           if (data.cursor_type == CURSOR_ON
  2360.           && (data.cursor_bufpos >= data.bufpos &&
  2361.               data.cursor_bufpos < next_bufpos))
  2362.         {
  2363.             data.cursor_type = NEXT_CURSOR;
  2364.         }
  2365.  
  2366.           /* We won't be adding a truncation or continuation glyph
  2367.                  so give up the room allocated for them. */
  2368.           data.max_pixpos += end_glyph_width;
  2369.  
  2370.           if (!NILP (b->selective_display_ellipses))
  2371.         {
  2372.           /* We don't propagate anything from the invisible
  2373.                      text glyph if it fails to fit.  This is
  2374.                      intentional. */
  2375.           struct glyph_block gb;
  2376.  
  2377.           gb.extent = Qnil;
  2378.           gb.glyph = Vinvisible_text_glyph;
  2379.           add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 1,
  2380.                   GLYPH_CACHE_ELEMENT (w, INVIS_GLYPH_INDEX));
  2381.         }
  2382.  
  2383.           /* Set the buffer position to the end of the line.  We
  2384.                  need to do this before potentially adding a newline
  2385.                  so that the cursor flag will get set correctly (if
  2386.                  needed). */
  2387.           data.bufpos = next_bufpos;
  2388.  
  2389.           if (NILP (b->selective_display_ellipses)
  2390.           || data.cursor_bufpos == next_bufpos)
  2391.         {
  2392.           /* We have to at least add a newline character so
  2393.                      that the cursor shows up properly. */
  2394.           data.ch = '\n';
  2395.           data.width = DEVMETH (d, eol_cursor_width, ());
  2396.           data.findex = DEFAULT_INDEX;
  2397.           data.start_col = 0;
  2398.           data.start_col_enabled = 0;
  2399.  
  2400.           add_emchar_rune (&data);
  2401.         }
  2402.  
  2403.           /* This had better be a newline but doing it this way
  2404.                  we'll see obvious incorrect results if it isn't.  No
  2405.                  need to abort here. */
  2406.           data.ch = BUF_FETCH_CHAR (b, data.bufpos);
  2407.  
  2408.           goto done;
  2409.         }
  2410.  
  2411.       /* If the current character is considered to be printable, then
  2412.              just add it. */
  2413.       else if (data.ch >= printable_min)
  2414.         {
  2415.           *prop = add_emchar_rune (&data);
  2416.           if (*prop)
  2417.         goto done;
  2418.         }
  2419.  
  2420.       /* If the current character is a tab, determine the next tab
  2421.              starting position and add a blank rune which extends from the
  2422.              current pixel position to that starting position. */
  2423.       else if (data.ch == '\t')
  2424.         {
  2425.           int old_width = data.width;
  2426.           int tab_start_pixpos = data.pixpos;
  2427.           int next_tab_start;
  2428.           int char_tab_width;
  2429.           int prop_width = 0;
  2430.  
  2431.           if (data.start_col > 1)
  2432.         tab_start_pixpos -= (space_width (w) * (data.start_col - 1));
  2433.  
  2434.           next_tab_start = next_tab_position (w, tab_start_pixpos,
  2435.                           dl->bounds.left_in);
  2436.           if (next_tab_start > data.max_pixpos)
  2437.         {
  2438.           prop_width = next_tab_start - data.max_pixpos;
  2439.           next_tab_start = data.max_pixpos;
  2440.         }
  2441.           data.width = next_tab_start - data.pixpos;
  2442.           char_tab_width =
  2443.         (next_tab_start - tab_start_pixpos) / space_width (w);
  2444.  
  2445.           *prop = add_blank_rune (&data, w, char_tab_width);
  2446.           data.width = old_width;
  2447.  
  2448.           /* add_blank_rune is only supposed to be called with
  2449.                  sizes guaranteed to fit in the available space. */
  2450.           assert (!(*prop));
  2451.  
  2452.           if (prop_width)
  2453.         {
  2454.           struct prop_block pb;
  2455.           *prop = Dynarr_new (struct prop_block);
  2456.  
  2457.           pb.type = PROP_BLANK;
  2458.           pb.data.p_blank.width = prop_width;
  2459.           pb.data.p_blank.findex = data.findex;
  2460.           Dynarr_add (*prop, pb);
  2461.  
  2462.           goto done;
  2463.         }
  2464.         }
  2465.  
  2466.       /* If character is a control character, pass it off to
  2467.              add_control_char_runes.
  2468.  
  2469.          The is_*() routines have undefined results on
  2470.          arguments outside of the range [-1, 255].  (This
  2471.          often bites people who carelessly use `char' instead
  2472.          of `unsigned char'.)
  2473.          */
  2474.       else if (data.ch < 0x100 && iscntrl ((Bufbyte) data.ch))
  2475.         {
  2476.           *prop = add_control_char_runes (&data, b);
  2477.  
  2478.           if (*prop)
  2479.         goto done;
  2480.         }
  2481.  
  2482.       /* If the character is above the ASCII range and we have not
  2483.              already handled it, then print it as an octal number. */
  2484.       else if (data.ch >= 0200)
  2485.         {
  2486.           *prop = add_octal_runes (&data);
  2487.  
  2488.           if (*prop)
  2489.         goto done;
  2490.         }
  2491.  
  2492.       /* Assume the current character is considered to be printable,
  2493.              then just add it. */
  2494.       else
  2495.         {
  2496.           *prop = add_emchar_rune (&data);
  2497.           if (*prop)
  2498.         goto done;
  2499.         }
  2500.  
  2501.       data.bufpos++;
  2502.     }
  2503.     }
  2504.  
  2505. done:
  2506.  
  2507.   /* Determine the starting point of the next line if we did not hit the
  2508.      end of the buffer. */
  2509.   if (data.bufpos < BUF_ZV (b)
  2510.       && (active_minibuffer || !NILP (Vsynchronize_minibuffers)))
  2511.     {
  2512.       /* #### This check is not correct.  If the line terminated
  2513.      due to a begin-glyph or end-glyph hitting window-end, then
  2514.      data.ch will not point to the character at data.bufpos.  If
  2515.      you make the two changes mentioned at the top of this loop,
  2516.      you should be able to say '(if (*prop))'.  That should also
  2517.      make it possible to eliminate the data.bufpos < BUF_ZV (b)
  2518.      check. */
  2519.  
  2520.       /* The common case is that the line ended because we hit a newline.
  2521.          In that case, the next character is just the next buffer
  2522.          position. */
  2523.       if (data.ch == '\n')
  2524.     {
  2525.       /* If data.start_col_enabled is still true, then the window is
  2526.              scrolled far enough so that nothing on this line is visible.
  2527.              We need to stick a trunctation glyph at the beginning of the
  2528.              line in that case unless the line is completely blank. */
  2529.       if (data.start_col_enabled)
  2530.         {
  2531.           if (data.cursor_type == CURSOR_ON)
  2532.         {
  2533.           if (data.cursor_bufpos >= start_pos
  2534.               && data.cursor_bufpos <= data.bufpos)
  2535.             data.cursor_bufpos = data.bufpos;
  2536.         }
  2537.           data.findex = DEFAULT_INDEX;
  2538.           data.start_col = 0;
  2539.           data.start_col_enabled = 0;
  2540.  
  2541.           if (data.bufpos != start_pos)
  2542.         {
  2543.           struct glyph_block gb;
  2544.  
  2545.           gb.extent = Qnil;
  2546.           gb.glyph = Vhscroll_glyph;
  2547.           add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 0,
  2548.                   GLYPH_CACHE_ELEMENT (w, HSCROLL_GLYPH_INDEX));
  2549.         }
  2550.           else
  2551.         {
  2552.           /* This duplicates code down below to add a newline to
  2553.                      the end of an otherwise empty line.*/
  2554.           data.ch = '\n';
  2555.           data.width = DEVMETH (d, eol_cursor_width, ());
  2556.  
  2557.           add_emchar_rune (&data);
  2558.         }
  2559.         }
  2560.  
  2561.       data.bufpos++;
  2562.     }
  2563.  
  2564.       /* Otherwise we have a buffer line which cannot fit on one display
  2565.          line. */
  2566.       else
  2567.     {
  2568.       struct glyph_block gb;
  2569.       struct glyph_cache_element *inst;
  2570.  
  2571.       /* If the line is to be truncated then we actually have to look
  2572.              for the next newline.  We also add the end-of-line glyph which
  2573.              we know will fit because we adjusted the right border before
  2574.              we starting laying out the line. */
  2575.       data.max_pixpos += end_glyph_width;
  2576.       data.findex = DEFAULT_INDEX;
  2577.       gb.extent = Qnil;
  2578.  
  2579.       if (truncate_win)
  2580.         {
  2581.           Bufpos pos;
  2582.  
  2583.           /* Now find the start of the next line. */
  2584.           pos = find_next_newline_no_quit (b, data.bufpos, 1);
  2585.  
  2586.           /* If the cursor is past the truncation line then we
  2587.                  make it appear on the truncation glyph.  If we've hit
  2588.                  the end of the buffer then we also make the cursor
  2589.                  appear unless eob is immediately preceeded by a
  2590.                  newline.  In that case the cursor should actually
  2591.                  appear on the next line. */
  2592.           if (data.cursor_type == CURSOR_ON 
  2593.           && data.cursor_bufpos >= data.bufpos
  2594.           && (data.cursor_bufpos < pos ||
  2595.               (pos == BUF_ZV (b)
  2596.                && (pos == BUF_BEGV (b)
  2597.                || BUF_FETCH_CHAR (b, pos - 1) != '\n'))))
  2598.         data.cursor_bufpos = pos;
  2599.           else
  2600.         data.cursor_type = NO_CURSOR;
  2601.  
  2602.           data.bufpos = pos;
  2603.           gb.glyph = Vtruncation_glyph;
  2604.           inst = GLYPH_CACHE_ELEMENT (w, TRUN_GLYPH_INDEX);
  2605.         }
  2606.       else
  2607.         {
  2608.           /* The cursor can never be on the continuation glyph. */
  2609.           data.cursor_type = NO_CURSOR;
  2610.  
  2611.           /* data.bufpos is already at the start of the next line. */
  2612.  
  2613.           gb.glyph = Vcontinuation_glyph;
  2614.           inst = GLYPH_CACHE_ELEMENT (w, CONT_GLYPH_INDEX);
  2615.         }
  2616.  
  2617.       add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 1, inst);
  2618.  
  2619.       if (truncate_win && data.bufpos == BUF_ZV (b)
  2620.           && BUF_FETCH_CHAR (b, BUF_ZV (b) - 1) != '\n')
  2621.         data.bufpos++;
  2622.     }
  2623.     }
  2624.   else if ((active_minibuffer || !NILP (Vsynchronize_minibuffers))
  2625.        && (!echo_area_active (f) || data.bufpos == BUF_ZV (b)))
  2626.     {
  2627.       /* We need to add a marker to the end of the line since there is no
  2628.          newline character in order for the cursor to get drawn.  We label
  2629.          it as a newline so that it gets handled correctly by the
  2630.          whitespace routines below. */
  2631.  
  2632.       data.ch = '\n';
  2633.       data.width = DEVMETH (d, eol_cursor_width, ());
  2634.       data.findex = DEFAULT_INDEX;
  2635.       data.start_col = 0;
  2636.       data.start_col_enabled = 0;
  2637.  
  2638.       data.max_pixpos += data.width;
  2639.       add_emchar_rune (&data);
  2640.       data.max_pixpos -= data.width;
  2641.  
  2642.       data.bufpos = BUF_ZV (b) + 1;
  2643.     }
  2644.  
  2645.   /* Calculate left whitespace boundary. */
  2646.   {
  2647.     int elt = 0;
  2648.  
  2649.     /* Whitespace past a newline is considered right whitespace. */
  2650.     while (elt < Dynarr_length (db->runes))
  2651.       {
  2652.     struct rune *rb = Dynarr_atp (db->runes, elt);
  2653.  
  2654.     if ((rb->type == CHAR && rb->object.ch == ' ') || rb->type == BLANK)
  2655.       {
  2656.         dl->bounds.left_white += rb->width;
  2657.         elt++;
  2658.       }
  2659.     else
  2660.       elt = Dynarr_length (db->runes);
  2661.       }
  2662.   }
  2663.  
  2664.   /* Calculate right whitespace boundary. */
  2665.   {
  2666.     int elt = Dynarr_length (db->runes) - 1;
  2667.     int done = 0;
  2668.  
  2669.     while (!done && elt >= 0)
  2670.       {
  2671.     struct rune *rb = Dynarr_atp (db->runes, elt);
  2672.  
  2673.     if (!(rb->type == CHAR && isspace (rb->object.ch))
  2674.         && !rb->type == BLANK)
  2675.       {
  2676.         dl->bounds.right_white = rb->xpos + rb->width;
  2677.         done = 1;
  2678.       }
  2679.  
  2680.     elt--;
  2681.  
  2682.       }
  2683.  
  2684.     /* The line is blank so everything is considered to be right
  2685.        whitespace. */
  2686.     if (!done)
  2687.       dl->bounds.right_white = dl->bounds.left_in;
  2688.   }
  2689.  
  2690.   /* Set the display blocks bounds. */
  2691.   db->start_pos = dl->bounds.left_in;
  2692.   if (Dynarr_length (db->runes))
  2693.     {
  2694.       struct rune *rb = Dynarr_atp (db->runes, Dynarr_length (db->runes) - 1);
  2695.  
  2696.       db->end_pos = rb->xpos + rb->width;
  2697.     }
  2698.   else
  2699.     db->end_pos = dl->bounds.right_white;
  2700.  
  2701.   /* update line height parameters */
  2702.   if (!data.new_ascent && !data.new_descent)
  2703.     {
  2704.       /* We've got a blank line so initialize these values from the default
  2705.          face. */
  2706.       struct font_metric_info fm;
  2707.  
  2708.       DEVMETH (d, font_metric_info,
  2709.            (d, FACE_CACHE_ELEMENT_FONT (w, DEFAULT_INDEX), &fm));
  2710.  
  2711.       data.new_ascent = fm.ascent;
  2712.       data.new_descent = fm.descent;
  2713.     }
  2714.  
  2715.   if (data.max_pixmap_height)
  2716.     {
  2717.       int height = data.new_ascent + data.new_descent;
  2718.       int pix_ascent, pix_descent;
  2719.  
  2720.       pix_descent = data.max_pixmap_height * data.new_descent / height;
  2721.       pix_ascent = data.max_pixmap_height - pix_descent;
  2722.  
  2723.       data.new_ascent = max (data.new_ascent, pix_ascent);
  2724.       data.new_descent = max (data.new_descent, pix_descent);
  2725.     }
  2726.  
  2727.   dl->ascent = data.new_ascent;
  2728.   dl->descent = data.new_descent;
  2729.  
  2730.   {
  2731.     unsigned short ascent = (unsigned short) XINT (w->minimum_line_ascent);
  2732.  
  2733.     if (dl->ascent < ascent)
  2734.       dl->ascent = ascent;
  2735.   }
  2736.   {
  2737.     unsigned short descent = (unsigned short) XINT (w->minimum_line_descent);
  2738.  
  2739.     if (dl->descent < descent)
  2740.       dl->descent = descent;
  2741.   }
  2742.  
  2743.   dl->cursor_elt = data.cursor_x;
  2744.   dl->end_bufpos = data.bufpos - 1;
  2745.   if (truncate_win)
  2746.     data.dl->num_chars = column_at_point (b, dl->end_bufpos, 0);
  2747.   else
  2748.     /* This doesn't correctly take into account tabs and control
  2749.        characters but if the window isn't being truncated then this
  2750.        value isn't going to end up being used anyhow. */
  2751.     data.dl->num_chars = dl->end_bufpos - dl->bufpos;
  2752.  
  2753.   /* #### handle horizontally scrolled line with text none of which
  2754.      was actually laid out. */
  2755.  
  2756.   /* #### handle any remainder of overlay arrow */
  2757.  
  2758.   if (*prop == ADD_FAILED)
  2759.     *prop = NULL;
  2760.  
  2761.   extent_fragment_delete (data.ef);
  2762.  
  2763.   /* #### If we started at EOB, then make sure we return a value past
  2764.      it so that regenerate_window will exit properly.  This is bogus.
  2765.      The main loop should get fixed so that it isn't necessary to call
  2766.      this function if we are already at EOB. */
  2767.  
  2768.   if (data.bufpos == BUF_ZV (b) && start_pos == BUF_ZV (b))
  2769.     return (data.bufpos + 1);
  2770.   else
  2771.     return data.bufpos;
  2772. }
  2773.  
  2774. /*****************************************************************************
  2775.  create_overlay_glyph_block
  2776.  
  2777.  Display the overlay arrow at the beginning of the given line.
  2778.  ****************************************************************************/
  2779. static int
  2780. create_overlay_glyph_block (struct window *w, struct display_line *dl)
  2781. {
  2782.   struct frame *f = XFRAME (w->frame);
  2783.   struct device *d = XDEVICE (f->device);
  2784.   pos_data data;
  2785.  
  2786.   /* If Voverlay_arrow_string isn't valid then just fail silently. */
  2787.   if (!STRINGP (Voverlay_arrow_string) && !GLYPHP (Voverlay_arrow_string))
  2788.     return 0;
  2789.  
  2790.   data.ef = NULL;
  2791.   data.d = d;
  2792.   XSETWINDOW (data.window, w);
  2793.   data.db = get_display_block_from_line (dl, OVERWRITE);
  2794.   data.dl = dl;
  2795.   data.bufpos = 0;
  2796.   data.endpos = 0;
  2797.   data.pixpos = dl->bounds.left_in;
  2798.   data.max_pixmap_height = 0;
  2799.   data.max_pixpos = dl->bounds.right_in;
  2800.   data.cursor_type = NO_CURSOR;
  2801.   data.cursor_x = -1;
  2802.   data.start_col = 0;
  2803.   data.start_col_enabled = 0;
  2804.   data.findex = DEFAULT_INDEX;
  2805.  
  2806.   DEVMETH (d, font_metric_info, (d, FACE_CACHE_ELEMENT_FONT (w, data.findex),
  2807.                  &data.fm));
  2808.   data.new_ascent = max ((int) dl->ascent, data.fm.ascent);
  2809.   data.new_descent = max ((int) dl->descent, data.fm.descent);
  2810.   if (data.fm.proportional)
  2811.     data.width = 0;
  2812.   else
  2813.     data.width = data.fm.width;
  2814.  
  2815.   Dynarr_reset (data.db->runes);
  2816.  
  2817.   if (STRINGP (Voverlay_arrow_string))
  2818.     {
  2819.       add_string_of_bufbyte_runes
  2820.     (&data,
  2821.      string_data (XSTRING (Voverlay_arrow_string)),
  2822.      string_length (XSTRING (Voverlay_arrow_string)),
  2823.      1);
  2824.     }
  2825.   else if (GLYPHP (Voverlay_arrow_string))
  2826.     {
  2827.       struct glyph_block gb;
  2828.  
  2829.       gb.glyph = Voverlay_arrow_string;
  2830.       gb.extent = Qnil;
  2831.       add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 0, 0);
  2832.     }
  2833.  
  2834.   if (data.max_pixmap_height)
  2835.     {
  2836.       int height = data.new_ascent + data.new_descent;
  2837.       int pix_ascent, pix_descent;
  2838.  
  2839.       pix_descent = data.max_pixmap_height * data.new_descent / height;
  2840.       pix_ascent = data.max_pixmap_height - pix_descent;
  2841.  
  2842.       data.new_ascent = max (data.new_ascent, pix_ascent);
  2843.       data.new_descent = max (data.new_descent, pix_descent);
  2844.     }
  2845.  
  2846.   dl->ascent = data.new_ascent;
  2847.   dl->descent = data.new_descent;
  2848.  
  2849.   data.db->start_pos = dl->bounds.left_in;
  2850.   data.db->end_pos = data.pixpos;
  2851.  
  2852.   return (data.pixpos - dl->bounds.left_in);
  2853. }
  2854.  
  2855. /*****************************************************************************
  2856.  add_margin_runes
  2857.  
  2858.  Add a type of glyph to a margin display block.
  2859.  ****************************************************************************/
  2860. static int
  2861. add_margin_runes (struct display_line *dl, struct display_block *db, int start,
  2862.           int count, int glyph_type, int side, Lisp_Object window)
  2863. {
  2864.   glyph_block_dynarr *gbd = (side == LEFT_GLYPHS
  2865.                  ? dl->left_glyphs
  2866.                  : dl->right_glyphs);
  2867.   int elt, end;
  2868.   int xpos = start;
  2869.   int reverse;
  2870.  
  2871.   if ((glyph_type == GL_WHITESPACE && side == LEFT_GLYPHS)
  2872.       || (glyph_type == GL_INSIDE_MARGIN && side == RIGHT_GLYPHS))
  2873.     {
  2874.       reverse = 1;
  2875.       elt = Dynarr_length (gbd) - 1;
  2876.       end = 0;
  2877.     }
  2878.   else
  2879.     {
  2880.       reverse = 0;
  2881.       elt = 0;
  2882.       end = Dynarr_length (gbd);
  2883.     }
  2884.  
  2885.   while (count && ((!reverse && elt < end) || (reverse && elt >= end)))
  2886.     {
  2887.       struct glyph_block *gb = Dynarr_atp (gbd, elt);
  2888.  
  2889.       if (NILP (gb->extent))
  2890.     abort ();    /* these should have been handled in add_glyph_rune */
  2891.  
  2892.       if (gb->active &&
  2893.       ((side == LEFT_GLYPHS &&
  2894.         extent_begin_glyph_layout (XEXTENT (gb->extent)) == glyph_type)
  2895.        || (side == RIGHT_GLYPHS &&
  2896.            extent_end_glyph_layout (XEXTENT (gb->extent)) == glyph_type)))
  2897.     {
  2898.       struct rune rb;
  2899.  
  2900.       rb.width = gb->width;
  2901.       rb.findex = gb->findex;
  2902.       rb.extent = gb->extent;
  2903.       rb.xpos = xpos;
  2904.       rb.bufpos = -1;
  2905.       rb.endpos = 0;
  2906.       rb.type = DGLYPH;
  2907.       rb.object.dglyph.glyph = gb->glyph;
  2908.       rb.object.dglyph.xoffset = 0;
  2909.       rb.cursor_type = CURSOR_OFF;
  2910.  
  2911.       Dynarr_add (db->runes, rb);
  2912.       xpos += rb.width;
  2913.       count--;
  2914.       gb->active = 0;
  2915.  
  2916.       if (glyph_contrib_p (gb->glyph, window))
  2917.         {
  2918.           unsigned short ascent, descent;
  2919.           Lisp_Object baseline = glyph_baseline (gb->glyph, window);
  2920.  
  2921.           ascent = glyph_ascent (gb->glyph, gb->findex, 0, window);
  2922.           descent = glyph_descent (gb->glyph, gb->findex, 0, window);
  2923.  
  2924.           /* A pixmap that has not had a baseline explicitly set.
  2925.                  We use the existing ascent / descent ratio of the
  2926.                  line. */
  2927.           if (NILP (baseline))
  2928.         {
  2929.           int gheight = ascent + descent;
  2930.           int line_height = dl->ascent + dl->descent;
  2931.           int pix_ascent, pix_descent;
  2932.  
  2933.           pix_descent = (int) (gheight * dl->descent) / line_height;
  2934.           pix_ascent = gheight - pix_descent;
  2935.  
  2936.           dl->ascent = max ((int) dl->ascent, pix_ascent);
  2937.           dl->descent = max ((int) dl->descent, pix_descent);
  2938.         }
  2939.  
  2940.           /* A string so determine contribution normally. */
  2941.           else if (EQ (baseline, Qt))
  2942.         {
  2943.           dl->ascent = max (dl->ascent, ascent);
  2944.           dl->descent = max (dl->descent, descent);
  2945.         }
  2946.  
  2947.           /* A pixmap with an explicitly set baseline.  We determine the
  2948.          contribution here. */
  2949.           else if (INTP (baseline))
  2950.         {
  2951.           int height = ascent + descent;
  2952.           int pix_ascent, pix_descent;
  2953.  
  2954.           pix_ascent = height * XINT (baseline) / 100;
  2955.           pix_descent = height - pix_ascent;
  2956.  
  2957.           dl->ascent = max ((int) dl->ascent, pix_ascent);
  2958.           dl->descent = max ((int) dl->descent, pix_descent);
  2959.         }
  2960.  
  2961.           /* Otherwise something is screwed up. */
  2962.           else
  2963.         abort ();
  2964.         }
  2965.     }
  2966.  
  2967.       (reverse ? elt-- : elt++);
  2968.     }
  2969.  
  2970.   return xpos;
  2971. }
  2972.  
  2973. /*****************************************************************************
  2974.  add_margin_blank
  2975.  
  2976.  Add a blank to a margin display block.
  2977.  ****************************************************************************/
  2978. static void
  2979. add_margin_blank (struct display_line *dl, struct display_block *db,
  2980.           struct window *w, int xpos, int width, int side)
  2981. {
  2982.   struct rune rb;
  2983.  
  2984.   rb.findex = (side == LEFT_GLYPHS
  2985.            ? get_builtin_face_cache_index (w, Vleft_margin_face)
  2986.            : get_builtin_face_cache_index (w, Vright_margin_face));
  2987.   rb.extent = Qnil;
  2988.   rb.xpos = xpos;
  2989.   rb.width = width;
  2990.   rb.bufpos = -1;
  2991.   rb.endpos = 0;
  2992.   rb.type = BLANK;
  2993.   rb.cursor_type = CURSOR_OFF;
  2994.  
  2995.   Dynarr_add (db->runes, rb);
  2996. }
  2997.  
  2998. /*****************************************************************************
  2999.  create_left_glyph_block
  3000.  
  3001.  Display glyphs in the left outside margin, left inside margin and
  3002.  left whitespace area.
  3003.  ****************************************************************************/
  3004. static void
  3005. create_left_glyph_block (struct window *w, struct display_line *dl,
  3006.              int overlay_width)
  3007. {
  3008.   Lisp_Object window;
  3009.  
  3010.   int use_overflow = (NILP (w->use_left_overflow) ? 0 : 1);
  3011.   int elt, end_xpos;
  3012.   int out_end, in_out_start, in_in_end, white_out_start, white_in_start;
  3013.   int out_cnt, in_out_cnt, in_in_cnt, white_out_cnt, white_in_cnt;
  3014.   int left_in_start = dl->bounds.left_in;
  3015.   int left_in_end = dl->bounds.left_in + overlay_width;
  3016.  
  3017.   struct display_block *odb, *idb;
  3018.  
  3019.   XSETWINDOW (window, w);
  3020.  
  3021.   /* We have to add the glyphs to the line in the order outside,
  3022.      inside, whitespace.  However the precedence dictates that we
  3023.      determine how many will fit in the reverse order. */
  3024.  
  3025.   /* Determine how many whitespace glyphs we can display and where
  3026.      they should start. */
  3027.   white_in_start = dl->bounds.left_white;
  3028.   white_out_start = left_in_start;
  3029.   white_out_cnt = white_in_cnt = 0;
  3030.   elt = 0;
  3031.  
  3032.   while (elt < Dynarr_length (dl->left_glyphs))
  3033.     {
  3034.       struct glyph_block *gb = Dynarr_atp (dl->left_glyphs, elt);
  3035.  
  3036.       if (NILP (gb->extent))
  3037.     abort ();    /* these should have been handled in add_glyph_rune */
  3038.  
  3039.       if (extent_begin_glyph_layout (XEXTENT (gb->extent)) == GL_WHITESPACE)
  3040.     {
  3041.       int width;
  3042.  
  3043.       width = glyph_width (gb->glyph, gb->findex, 0, window);
  3044.  
  3045.       if (white_in_start - width >= left_in_end)
  3046.         {
  3047.           white_in_cnt++;
  3048.           white_in_start -= width;
  3049.           gb->width = width;
  3050.           gb->active = 1;
  3051.         }
  3052.       else if (use_overflow
  3053.            && (white_out_start - width > dl->bounds.left_out))
  3054.         {
  3055.           white_out_cnt++;
  3056.           white_out_start -= width;
  3057.           gb->width = width;
  3058.           gb->active = 1;
  3059.         }
  3060.       else
  3061.         gb->active = 0;
  3062.     }
  3063.  
  3064.       elt++;
  3065.     }
  3066.  
  3067.   /* Determine how many inside margin glyphs we can display and where
  3068.      they should start.  The inside margin glyphs get whatever space
  3069.      is left after the whitespace glyphs have been displayed.  These
  3070.      are tricky to calculate since if we decide to use the overflow
  3071.      area we basicaly have to start over.  So for these we build up a
  3072.      list of just the inside margin glyphs and manipulate it to
  3073.      determine the needed info. */
  3074.   {
  3075.     glyph_block_dynarr *ib;
  3076.     int avail_in, avail_out;
  3077.     int done = 0;
  3078.     int marker = 0;
  3079.     int used_in, used_out;
  3080.  
  3081.     elt = 0;
  3082.     used_in = used_out = 0;
  3083.     ib = Dynarr_new (struct glyph_block);
  3084.     while (elt < Dynarr_length (dl->left_glyphs))
  3085.       {
  3086.     struct glyph_block *gb = Dynarr_atp (dl->left_glyphs, elt);
  3087.  
  3088.     if (NILP (gb->extent))
  3089.       abort ();    /* these should have been handled in add_glyph_rune */
  3090.  
  3091.     if (extent_begin_glyph_layout (XEXTENT (gb->extent)) ==
  3092.         GL_INSIDE_MARGIN)
  3093.       {
  3094.         gb->width = glyph_width (gb->glyph, gb->findex, 0, window);
  3095.         used_in += gb->width;
  3096.         Dynarr_add (ib, *gb);
  3097.       }
  3098.  
  3099.     elt++;
  3100.       }
  3101.  
  3102.     if (white_out_cnt)
  3103.       avail_in = 0;
  3104.     else
  3105.       {
  3106.     avail_in = white_in_start - left_in_end;
  3107.     if (avail_in < 0)
  3108.       avail_in = 0;
  3109.       }
  3110.  
  3111.     if (!use_overflow)
  3112.       avail_out = 0;
  3113.     else
  3114.       avail_out = white_out_start - dl->bounds.left_out;
  3115.  
  3116.     marker = 0;
  3117.     while (!done && marker < Dynarr_length (ib))
  3118.       {
  3119.     int width = Dynarr_atp (ib, marker)->width;
  3120.  
  3121.     /* If everything now fits in the available inside margin
  3122.            space, we're done. */
  3123.     if (used_in <= avail_in)
  3124.       done = 1;
  3125.     else
  3126.       {
  3127.         /* Otherwise see if we have room to move a glyph to the
  3128.                outside. */
  3129.         if (used_out + width <= avail_out)
  3130.           {
  3131.         used_out += width;
  3132.         used_in -= width;
  3133.           }
  3134.         else
  3135.           done = 1;
  3136.       }
  3137.  
  3138.     if (!done)
  3139.       marker++;
  3140.       }
  3141.  
  3142.     /* At this point we now know that everything from marker on goes in
  3143.        the inside margin and everything before it goes in the outside
  3144.        margin.  The stuff going into the outside margin is guaranteed
  3145.        to fit, but we may have to trim some stuff from the inside. */
  3146.  
  3147.     in_in_end = left_in_end;
  3148.     in_out_start = white_out_start;
  3149.     in_out_cnt = in_in_cnt = 0;
  3150.  
  3151.     Dynarr_free (ib);
  3152.     elt = 0;
  3153.     while (elt < Dynarr_length (dl->left_glyphs))
  3154.       {
  3155.     struct glyph_block *gb = Dynarr_atp (dl->left_glyphs, elt);
  3156.  
  3157.     if (NILP (gb->extent))
  3158.       abort ();    /* these should have been handled in add_glyph_rune */
  3159.  
  3160.     if (extent_begin_glyph_layout (XEXTENT (gb->extent)) ==
  3161.         GL_INSIDE_MARGIN)
  3162.       {
  3163.         int width = glyph_width (gb->glyph, gb->findex, 0, window);
  3164.  
  3165.         if (used_out)
  3166.           {
  3167.         in_out_cnt++;
  3168.         in_out_start -= width;
  3169.         gb->width = width;
  3170.         gb->active = 1;
  3171.         used_out -= width;
  3172.           }
  3173.         else if (in_in_end + width < white_in_start)
  3174.           {
  3175.         in_in_cnt++;
  3176.         in_in_end += width;
  3177.         gb->width = width;
  3178.         gb->active = 1;
  3179.           }
  3180.         else
  3181.           gb->active = 0;
  3182.       }
  3183.  
  3184.     elt++;
  3185.       }
  3186.   }
  3187.  
  3188.   /* Determine how many outside margin glyphs we can display.  They
  3189.      always start at the left outside margin and can only use the
  3190.      outside margin space. */
  3191.   out_end = dl->bounds.left_out;
  3192.   out_cnt = 0;
  3193.   elt = 0;
  3194.  
  3195.   while (elt < Dynarr_length (dl->left_glyphs))
  3196.     {
  3197.       struct glyph_block *gb = Dynarr_atp (dl->left_glyphs, elt);
  3198.  
  3199.       if (NILP (gb->extent))
  3200.     abort ();    /* these should have beeb handled in add_glyph_rune */
  3201.  
  3202.       if (extent_begin_glyph_layout (XEXTENT (gb->extent)) ==
  3203.       GL_OUTSIDE_MARGIN)
  3204.     {
  3205.       int width = glyph_width (gb->glyph, gb->findex, 0, window);
  3206.  
  3207.       if (out_end + width < in_out_start)
  3208.         {
  3209.           out_cnt++;
  3210.           out_end += width;
  3211.           gb->width = width;
  3212.           gb->active = 1;
  3213.         }
  3214.       else
  3215.         gb->active = 0;
  3216.     }
  3217.  
  3218.       elt++;
  3219.     }
  3220.  
  3221.   /* Now that we now where everything goes, we add the glyphs as runes
  3222.      to the appropriate display blocks. */
  3223.   if (out_cnt || in_out_cnt || white_out_cnt)
  3224.     {
  3225.       odb = get_display_block_from_line (dl, LEFT_OUTSIDE_MARGIN);
  3226.       odb->start_pos = dl->bounds.left_out;
  3227.       /* #### We should stop adding a blank to account for the space
  3228.          between the end of the glyphs and the margin and instead set
  3229.          this accordingly. */
  3230.       odb->end_pos = dl->bounds.left_in;
  3231.       Dynarr_reset (odb->runes);
  3232.     }
  3233.   else
  3234.     odb = 0;
  3235.  
  3236.   if (in_in_cnt || white_in_cnt)
  3237.     {
  3238.       idb = get_display_block_from_line (dl, LEFT_INSIDE_MARGIN);
  3239.       idb->start_pos = dl->bounds.left_in;
  3240.       /* #### See above comment for odb->end_pos */
  3241.       idb->end_pos = dl->bounds.left_white;
  3242.       Dynarr_reset (idb->runes);
  3243.     }
  3244.   else
  3245.     idb = 0;
  3246.  
  3247.   /* First add the outside margin glyphs. */
  3248.   if (out_cnt)
  3249.     end_xpos = add_margin_runes (dl, odb, dl->bounds.left_out, out_cnt,
  3250.                  GL_OUTSIDE_MARGIN, LEFT_GLYPHS, window);
  3251.   else
  3252.     end_xpos = dl->bounds.left_out;
  3253.  
  3254.   /* There may be blank space between the outside margin glyphs and
  3255.      the inside margin glyphs.  If so, add a blank. */
  3256.   if (in_out_cnt && (in_out_start - end_xpos))
  3257.     {
  3258.       add_margin_blank (dl, odb, w, end_xpos, in_out_start - end_xpos,
  3259.             LEFT_GLYPHS);
  3260.     }
  3261.  
  3262.   /* Next add the inside margin glyphs which are actually in the
  3263.      outside margin. */
  3264.   if (in_out_cnt)
  3265.     {
  3266.       end_xpos = add_margin_runes (dl, odb, in_out_start, in_out_cnt,
  3267.                    GL_INSIDE_MARGIN, LEFT_GLYPHS, window);
  3268.     }
  3269.  
  3270.   /* If we didn't add any inside margin glyphs to the outside margin,
  3271.      but are adding whitespace glyphs, then we need to add a blank
  3272.      here. */
  3273.   if (!in_out_cnt && white_out_cnt && (white_out_start - end_xpos))
  3274.     {
  3275.       add_margin_blank (dl, odb, w, end_xpos, white_out_start - end_xpos,
  3276.             LEFT_GLYPHS);
  3277.     }
  3278.  
  3279.   /* Next add the whitespace margin glyphs which are actually in the
  3280.      outside margin. */
  3281.   if (white_out_cnt)
  3282.     {
  3283.       end_xpos = add_margin_runes (dl, odb, white_out_start, white_out_cnt,
  3284.                    GL_WHITESPACE, LEFT_GLYPHS, window);
  3285.     }
  3286.  
  3287.   /* We take care of clearing between the end of the glyphs and the
  3288.      start of the inside margin for lines which have glyphs.  */
  3289.   if (odb && (left_in_start - end_xpos))
  3290.     {
  3291.       add_margin_blank (dl, odb, w, end_xpos, left_in_start - end_xpos,
  3292.             LEFT_GLYPHS);
  3293.     }
  3294.  
  3295.   /* Next add the inside margin glyphs which are actually in the
  3296.      inside margin. */
  3297.   if (in_in_cnt)
  3298.     {
  3299.       end_xpos = add_margin_runes (dl, idb, left_in_end, in_in_cnt,
  3300.                    GL_INSIDE_MARGIN, LEFT_GLYPHS, window);
  3301.     }
  3302.   else
  3303.     end_xpos = left_in_end;
  3304.  
  3305.   /* Make sure that the area between the end of the inside margin
  3306.      glyphs and the whitespace glyphs is cleared. */
  3307.   if (idb && (white_in_start - end_xpos > 0))
  3308.     {
  3309.       add_margin_blank (dl, idb, w, end_xpos, white_in_start - end_xpos,
  3310.             LEFT_GLYPHS);
  3311.     }
  3312.  
  3313.   /* Next add the whitespace margin glyphs which are actually in the
  3314.      inside margin. */
  3315.   if (white_in_cnt)
  3316.     {
  3317.       add_margin_runes (dl, idb, white_in_start, white_in_cnt, GL_WHITESPACE,
  3318.             LEFT_GLYPHS, window);
  3319.     }
  3320.  
  3321.   /* Whitespace glyphs always end right next to the text block so
  3322.      there is nothing we have to make sure is cleared after them. */
  3323. }
  3324.  
  3325. /*****************************************************************************
  3326.  create_right_glyph_block
  3327.  
  3328.  Display glyphs in the right outside margin, right inside margin and
  3329.  right whitespace area.
  3330.  ****************************************************************************/
  3331. static void
  3332. create_right_glyph_block (struct window *w, struct display_line *dl)
  3333. {
  3334.   Lisp_Object window;
  3335.  
  3336.   int use_overflow = (NILP (w->use_right_overflow) ? 0 : 1);
  3337.   int elt, end_xpos;
  3338.   int out_start, in_out_end, in_in_start, white_out_end, white_in_end;
  3339.   int out_cnt, in_out_cnt, in_in_cnt, white_out_cnt, white_in_cnt;
  3340.  
  3341.   struct display_block *odb, *idb;
  3342.  
  3343.   XSETWINDOW (window, w);
  3344.  
  3345.   /* We have to add the glyphs to the line in the order outside,
  3346.      inside, whitespace.  However the precedence dictates that we
  3347.      determine how many will fit in the reverse order. */
  3348.  
  3349.   /* Determine how many whitespace glyphs we can display and where
  3350.      they should start. */
  3351.   white_in_end = dl->bounds.right_white;
  3352.   white_out_end = dl->bounds.right_in;
  3353.   white_out_cnt = white_in_cnt = 0;
  3354.   elt = 0;
  3355.  
  3356.   while (elt < Dynarr_length (dl->right_glyphs))
  3357.     {
  3358.       struct glyph_block *gb = Dynarr_atp (dl->right_glyphs, elt);
  3359.  
  3360.       if (NILP (gb->extent))
  3361.     abort ();    /* these should have been handled in add_glyph_rune */
  3362.  
  3363.       if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_WHITESPACE)
  3364.     {
  3365.       int width = glyph_width (gb->glyph, gb->findex, 0, window);
  3366.  
  3367.       if (white_in_end + width <= dl->bounds.right_in)
  3368.         {
  3369.           white_in_cnt++;
  3370.           white_in_end += width;
  3371.           gb->width = width;
  3372.           gb->active = 1;
  3373.         }
  3374.       else if (use_overflow
  3375.            && (white_out_end + width <= dl->bounds.right_out))
  3376.         {
  3377.           white_out_cnt++;
  3378.           white_out_end += width;
  3379.           gb->width = width;
  3380.           gb->active = 1;
  3381.         }
  3382.       else
  3383.         gb->active = 0;
  3384.     }
  3385.  
  3386.       elt++;
  3387.     }
  3388.  
  3389.   /* Determine how many inside margin glyphs we can display and where
  3390.      they should start.  The inside margin glyphs get whatever space
  3391.      is left after the whitespace glyphs have been displayed.  These
  3392.      are tricky to calculate since if we decide to use the overflow
  3393.      area we basicaly have to start over.  So for these we build up a
  3394.      list of just the inside margin glyphs and manipulate it to
  3395.      determine the needed info. */
  3396.   {
  3397.     glyph_block_dynarr *ib;
  3398.     int avail_in, avail_out;
  3399.     int done = 0;
  3400.     int marker = 0;
  3401.     int used_in, used_out;
  3402.  
  3403.     elt = 0;
  3404.     used_in = used_out = 0;
  3405.     ib = Dynarr_new (struct glyph_block);
  3406.     while (elt < Dynarr_length (dl->right_glyphs))
  3407.       {
  3408.     struct glyph_block *gb = Dynarr_atp (dl->right_glyphs, elt);
  3409.  
  3410.     if (NILP (gb->extent))
  3411.       abort ();    /* these should have been handled in add_glyph_rune */
  3412.  
  3413.     if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_INSIDE_MARGIN)
  3414.       {
  3415.         gb->width = glyph_width (gb->glyph, gb->findex, 0, window);
  3416.         used_in += gb->width;
  3417.         Dynarr_add (ib, *gb);
  3418.       }
  3419.  
  3420.     elt++;
  3421.       }
  3422.  
  3423.     if (white_out_cnt)
  3424.       avail_in = 0;
  3425.     else
  3426.       avail_in = dl->bounds.right_in - white_in_end;
  3427.  
  3428.     if (!use_overflow)
  3429.       avail_out = 0;
  3430.     else
  3431.       avail_out = dl->bounds.right_out - white_out_end;
  3432.  
  3433.     marker = 0;
  3434.     while (!done && marker < Dynarr_length (ib))
  3435.       {
  3436.     int width = Dynarr_atp (ib, marker)->width;
  3437.  
  3438.     /* If everything now fits in the available inside margin
  3439.            space, we're done. */
  3440.     if (used_in <= avail_in)
  3441.       done = 1;
  3442.     else
  3443.       {
  3444.         /* Otherwise see if we have room to move a glyph to the
  3445.                outside. */
  3446.         if (used_out + width <= avail_out)
  3447.           {
  3448.         used_out += width;
  3449.         used_in -= width;
  3450.           }
  3451.         else
  3452.           done = 1;
  3453.       }
  3454.  
  3455.     if (!done)
  3456.       marker++;
  3457.       }
  3458.  
  3459.     /* At this point we now know that everything from marker on goes in
  3460.        the inside margin and everything before it goes in the outside
  3461.        margin.  The stuff going into the outside margin is guaranteed
  3462.        to fit, but we may have to trim some stuff from the inside. */
  3463.  
  3464.     in_in_start = dl->bounds.right_in;
  3465.     in_out_end = dl->bounds.right_in;
  3466.     in_out_cnt = in_in_cnt = 0;
  3467.  
  3468.     Dynarr_free (ib);
  3469.     elt = 0;
  3470.     while (elt < Dynarr_length (dl->right_glyphs))
  3471.       {
  3472.     struct glyph_block *gb = Dynarr_atp (dl->right_glyphs, elt);
  3473.  
  3474.     if (NILP (gb->extent))
  3475.       abort ();    /* these should have been handled in add_glyph_rune */
  3476.  
  3477.     if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_INSIDE_MARGIN)
  3478.       {
  3479.         int width = glyph_width (gb->glyph, gb->findex, 0, window);
  3480.  
  3481.         if (used_out)
  3482.           {
  3483.         in_out_cnt++;
  3484.         in_out_end += width;
  3485.         gb->width = width;
  3486.         gb->active = 1;
  3487.         used_out -= width;
  3488.           }
  3489.         else if (in_in_start - width >= white_in_end)
  3490.           {
  3491.         in_in_cnt++;
  3492.         in_in_start -= width;
  3493.         gb->width = width;
  3494.         gb->active = 1;
  3495.           }
  3496.         else
  3497.           gb->active = 0;
  3498.       }
  3499.  
  3500.     elt++;
  3501.       }
  3502.   }
  3503.  
  3504.   /* Determine how many outside margin glyphs we can display.  They
  3505.      always start at the right outside margin and can only use the
  3506.      outside margin space. */
  3507.   out_start = dl->bounds.right_out;
  3508.   out_cnt = 0;
  3509.   elt = 0;
  3510.  
  3511.   while (elt < Dynarr_length (dl->right_glyphs))
  3512.     {
  3513.       struct glyph_block *gb = Dynarr_atp (dl->right_glyphs, elt);
  3514.  
  3515.       if (NILP (gb->extent))
  3516.     abort ();    /* these should have beeb handled in add_glyph_rune */
  3517.  
  3518.       if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_OUTSIDE_MARGIN)
  3519.     {
  3520.       int width = glyph_width (gb->glyph, gb->findex, 0, window);
  3521.  
  3522.       if (out_start - width >= in_out_end)
  3523.         {
  3524.           out_cnt++;
  3525.           out_start -= width;
  3526.           gb->width = width;
  3527.           gb->active = 1;
  3528.         }
  3529.       else
  3530.         gb->active = 0;
  3531.     }
  3532.  
  3533.       elt++;
  3534.     }
  3535.  
  3536.   /* Now that we now where everything goes, we add the glyphs as runes
  3537.      to the appropriate display blocks. */
  3538.   if (out_cnt || in_out_cnt || white_out_cnt)
  3539.     {
  3540.       odb = get_display_block_from_line (dl, RIGHT_OUTSIDE_MARGIN);
  3541.       /* #### See comments before odb->start_pos init in
  3542.          create_left_glyph_block */
  3543.       odb->start_pos = dl->bounds.right_in;
  3544.       odb->end_pos = dl->bounds.right_out;
  3545.       Dynarr_reset (odb->runes);
  3546.     }
  3547.   else
  3548.     odb = 0;
  3549.  
  3550.   if (in_in_cnt || white_in_cnt)
  3551.     {
  3552.       idb = get_display_block_from_line (dl, RIGHT_INSIDE_MARGIN);
  3553.       idb->start_pos = dl->bounds.right_white;
  3554.       /* #### See comments before odb->start_pos init in
  3555.          create_left_glyph_block */
  3556.       idb->end_pos = dl->bounds.right_in;
  3557.       Dynarr_reset (idb->runes);
  3558.     }
  3559.   else
  3560.     idb = 0;
  3561.  
  3562.   /* First add the whitespace margin glyphs which are actually in the
  3563.      inside margin. */
  3564.   if (white_in_cnt)
  3565.     {
  3566.       end_xpos = add_margin_runes (dl, idb, dl->bounds.right_white,
  3567.                    white_in_cnt, GL_WHITESPACE, RIGHT_GLYPHS,
  3568.                    window);
  3569.     }
  3570.   else
  3571.     end_xpos = dl->bounds.right_white;
  3572.  
  3573.   /* Make sure that the area between the end of the whitespace glyphs
  3574.      and the inside margin glyphs is cleared. */
  3575.   if (in_in_cnt && (in_in_start - end_xpos))
  3576.     {
  3577.       add_margin_blank (dl, idb, w, end_xpos, in_in_start - end_xpos,
  3578.             RIGHT_GLYPHS);
  3579.     }
  3580.  
  3581.   /* Next add the inside margin glyphs which are actually in the
  3582.      inside margin. */
  3583.   if (in_in_cnt)
  3584.     {
  3585.       end_xpos = add_margin_runes (dl, idb, in_in_start, in_in_cnt,
  3586.                    GL_INSIDE_MARGIN, RIGHT_GLYPHS, window);
  3587.     }
  3588.  
  3589.   /* If we didn't add any inside margin glyphs then make sure the rest
  3590.      of the inside margin area gets cleared. */
  3591.   if (idb && (dl->bounds.right_in - end_xpos))
  3592.     {
  3593.       add_margin_blank (dl, idb, w, end_xpos, dl->bounds.right_in - end_xpos,
  3594.             RIGHT_GLYPHS);
  3595.     }
  3596.  
  3597.   /* Next add any whitespace glyphs in the outside margin. */
  3598.   if (white_out_cnt)
  3599.     {
  3600.       end_xpos = add_margin_runes (dl, odb, dl->bounds.right_in, white_out_cnt,
  3601.                    GL_WHITESPACE, RIGHT_GLYPHS, window);
  3602.     }
  3603.   else
  3604.     end_xpos = dl->bounds.right_in;
  3605.  
  3606.   /* Next add any inside margin glyphs in the outside margin. */
  3607.   if (in_out_cnt)
  3608.     {
  3609.       end_xpos = add_margin_runes (dl, odb, end_xpos, in_out_cnt,
  3610.                    GL_INSIDE_MARGIN, RIGHT_GLYPHS, window);
  3611.     }
  3612.  
  3613.   /* There may be space between any whitespace or inside margin glyphs
  3614.      in the outside margin and the actual outside margin glyphs. */
  3615.   if (odb && (out_start - end_xpos))
  3616.     {
  3617.       add_margin_blank (dl, odb, w, end_xpos, out_start - end_xpos,
  3618.             RIGHT_GLYPHS);
  3619.     }
  3620.  
  3621.   /* Finally, add the outside margin glyphs. */
  3622.   if (out_cnt)
  3623.     {
  3624.       add_margin_runes (dl, odb, out_start, out_cnt, GL_OUTSIDE_MARGIN,
  3625.             RIGHT_GLYPHS, window);
  3626.     }
  3627. }
  3628.  
  3629. /*****************************************************************************
  3630.  regenerate_window
  3631.  
  3632.  For a given window and starting position in the buffer it contains,
  3633.  ensure that the TYPE display lines accurately represent the
  3634.  presentation of the window.  We pass the buffer instead of getting it
  3635.  from the window since redisplay_window may have temporarily changed
  3636.  it to the echo area buffer.
  3637.  ****************************************************************************/
  3638. void
  3639. regenerate_window (struct window *w, Bufpos start_pos, Bufpos point, int type)
  3640. {
  3641.   struct frame *f = XFRAME (w->frame);
  3642.   struct buffer *b = XBUFFER (w->buffer);
  3643.   int ypos = WINDOW_TEXT_TOP (w);
  3644.   int yend = WINDOW_TEXT_BOTTOM (w);
  3645.  
  3646.   prop_block_dynarr *prop;
  3647.   layout_bounds bounds;
  3648.   display_line_dynarr *dla;
  3649.   struct display_line modeline;
  3650.   struct display_line *mlp = 0;
  3651.   int need_modeline;
  3652.  
  3653.   /* The lines had better exist by this point. */
  3654.   if (!(dla = window_display_lines (w, type)))
  3655.     abort ();
  3656.   Dynarr_reset (dla);
  3657.   w->max_line_len = 0;
  3658.  
  3659.   /* Normally these get updated in redisplay_window but it is possible
  3660.      for this function to get called from some other points where that
  3661.      update may not have occurred.  This acts as a safety check. */
  3662.   if (!Dynarr_length (w->face_cache_elements))
  3663.     reset_face_cache_elements (w);
  3664.   if (!Dynarr_length (w->glyph_cache_elements))
  3665.     reset_glyph_cache_elements (w);
  3666.  
  3667.   Fset_marker (w->start[type], make_number (start_pos), w->buffer);
  3668.   Fset_marker (w->pointm[type], make_number (point), w->buffer);
  3669.   w->last_point_x[type] = -1;
  3670.   w->last_point_y[type] = -1;
  3671.  
  3672.   /* minibuffer windows don't have modelines */
  3673.   if (MINI_WINDOW_P (w))
  3674.     need_modeline = 0;
  3675.   /* windows which haven't had it turned off do */
  3676.   else if (WINDOW_HAS_MODELINE_P (w))
  3677.     need_modeline = 1;
  3678.   /* windows which have it turned off don't have a divider if there is
  3679.      a horizontal scrollbar */
  3680.   else if (window_scrollbar_height (w))
  3681.     need_modeline = 0;
  3682.   /* and in this case there is none */
  3683.   else
  3684.     need_modeline = 1;
  3685.  
  3686.   /* Add a place marker for the modeline.  We wait to generate it
  3687.      until after we generate the rest of the window because it depends
  3688.      on values generated by doing just that. */
  3689.   if (need_modeline)
  3690.     {
  3691.       if (Dynarr_largest (dla) > 0)
  3692.     mlp = Dynarr_atp (dla, 0);
  3693.       else
  3694.     {
  3695.       memset (&modeline, 0, sizeof (struct display_line));
  3696.     }
  3697.  
  3698.       if (mlp)
  3699.     Dynarr_add (dla, *mlp);
  3700.       else
  3701.     Dynarr_add (dla, modeline);
  3702.     }
  3703.  
  3704.   bounds = calculate_display_line_boundaries (w, 0);
  3705.  
  3706.   if (MINI_WINDOW_P (w)
  3707.       && !NILP (Vminibuf_prompt)
  3708.       && !echo_area_active (f)
  3709.       && start_pos == BUF_BEGV (b))
  3710.     {
  3711.       struct prop_block pb;
  3712.       prop = Dynarr_new (struct prop_block);
  3713.  
  3714.       pb.type = PROP_MINIBUF_PROMPT;
  3715.       pb.data.p_string.str = string_data (XSTRING (Vminibuf_prompt));
  3716.       pb.data.p_string.len = string_length (XSTRING (Vminibuf_prompt));
  3717.       pb.data.p_string.pos = 0;
  3718.       Dynarr_add (prop, pb);
  3719.     }
  3720.   else
  3721.     prop = 0;
  3722.  
  3723.   while (ypos < yend)
  3724.     {
  3725.       struct display_line dl;
  3726.       struct display_line *dlp;
  3727.       int local;
  3728.  
  3729.       if (Dynarr_length (dla) < Dynarr_largest (dla))
  3730.     {
  3731.       dlp = Dynarr_atp (dla, Dynarr_length (dla));
  3732.       local = 0;
  3733.     }
  3734.       else
  3735.     {
  3736.       dlp = &dl;
  3737.       memset (dlp, 0, sizeof (struct display_line));
  3738.       local = 1;
  3739.     }
  3740.  
  3741.       dlp->bounds = bounds;
  3742.       dlp->offset = 0;
  3743.       start_pos = generate_display_line (w, dlp, 1, start_pos,
  3744.                      w->hscroll, &prop, type);
  3745.       dlp->ypos = ypos + dlp->ascent;
  3746.       ypos = dlp->ypos + dlp->descent;
  3747.  
  3748.       if (ypos > yend)
  3749.     {
  3750.       int visible_height = dlp->ascent + dlp->descent;
  3751.  
  3752.       dlp->clip = (ypos - yend);
  3753.       visible_height -= dlp->clip;
  3754.  
  3755.       if (visible_height < VERTICAL_CLIP (w, 1))
  3756.         {
  3757.           if (local)
  3758.         free_display_line (dlp);
  3759.           break;
  3760.         }
  3761.     }
  3762.       else
  3763.     dlp->clip = 0;
  3764.  
  3765.       if (dlp->cursor_elt != -1)
  3766.     {
  3767.       /* #### This check is steaming crap.  Have to get things
  3768.              fixed so when create_text_block hits EOB, we're done,
  3769.              period. */
  3770.       if (w->last_point_x[type] == -1)
  3771.         {
  3772.           w->last_point_x[type] = dlp->cursor_elt;
  3773.           w->last_point_y[type] = Dynarr_length (dla);
  3774.         }
  3775.       else
  3776.         {
  3777.           /* #### This means that we've added a cursor at EOB
  3778.                  twice.  Yuck oh yuck. */
  3779.           struct display_block *db =
  3780.         get_display_block_from_line (dlp, TEXT);
  3781.  
  3782.           Dynarr_atp (db->runes, dlp->cursor_elt)->cursor_type = NO_CURSOR;
  3783.           dlp->cursor_elt = -1;
  3784.         }
  3785.     }
  3786.  
  3787.       if (dlp->num_chars > w->max_line_len)
  3788.     w->max_line_len = dlp->num_chars;
  3789.  
  3790.       Dynarr_add (dla, *dlp);
  3791.  
  3792.       /* #### This isn't right, but it is close enough for now. */
  3793.       w->window_end_pos[type] = start_pos;
  3794.  
  3795.       /* #### This type of check needs to be done down in the
  3796.      generate_display_line call. */
  3797.       if (start_pos > BUF_ZV (b))
  3798.     break;
  3799.     }
  3800.  
  3801.   if (prop)
  3802.     Dynarr_free (prop);
  3803.  
  3804.   /* #### More not quite right, but close enough. */
  3805.   /* #### Ben sez: apparently window_end_pos[] is measured
  3806.      as the number of characters between the window end and the
  3807.      end of the buffer?  This seems rather weirdo.  What's
  3808.      the justification for this? */
  3809.   w->window_end_pos[type] = BUF_Z (b) - w->window_end_pos[type];
  3810.  
  3811.   if (need_modeline)
  3812.     {
  3813.       /* We know that this is the right thing to use because we put it
  3814.          there when we first started working in this function. */
  3815.       mlp = Dynarr_atp (dla, 0);
  3816.       generate_modeline (w, mlp, type);
  3817.     }
  3818. }
  3819.  
  3820. /*****************************************************************************
  3821.  regenerate_modeline
  3822.  
  3823.  Update just the modeline.  Assumes the desired display structs.  If
  3824.  they do not have a modeline block, it does nothing.
  3825.  ****************************************************************************/
  3826. static void
  3827. regenerate_modeline (struct window *w)
  3828. {
  3829.   display_line_dynarr *dla = window_display_lines (w, DESIRED_DISP);
  3830.  
  3831.   if (!Dynarr_length (dla) || !Dynarr_atp (dla, 0)->modeline)
  3832.     return;
  3833.   else
  3834.     {
  3835.       generate_modeline (w, Dynarr_atp (dla, 0), DESIRED_DISP);
  3836.       redisplay_update_line (w, 0, 0, 0);
  3837.     }
  3838. }
  3839.  
  3840. #define REGEN_INC_FIND_START_END        \
  3841.   do {                        \
  3842.     /* Determine start and end of lines. */    \
  3843.     if (!Dynarr_length (cdla))            \
  3844.       return 0;                    \
  3845.     else                    \
  3846.       {                        \
  3847.     if (Dynarr_atp (cdla, 0)->modeline && Dynarr_atp (ddla, 0)->modeline) \
  3848.       {                    \
  3849.         dla_start = 1;            \
  3850.       }                    \
  3851.     else if (!Dynarr_atp (cdla, 0)->modeline \
  3852.          && !Dynarr_atp (ddla, 0)->modeline) \
  3853.       {                    \
  3854.         dla_start = 0;            \
  3855.       }                    \
  3856.     else                    \
  3857.       abort ();    /* structs differ */    \
  3858.                         \
  3859.     dla_end = Dynarr_length (cdla) - 1;    \
  3860.       }                        \
  3861.                         \
  3862.     start_pos = (Dynarr_atp (cdla, dla_start)->bufpos \
  3863.          + Dynarr_atp (cdla, dla_start)->offset); \
  3864.     /* If this isn't true, then startp has changed and we need to do a \
  3865.        full regen. */                \
  3866.     if (startp != start_pos)            \
  3867.       return 0;                    \
  3868.                         \
  3869.     /* Point is outside the visible region so give up. */ \
  3870.     if (pointm < start_pos)            \
  3871.       return 0;                    \
  3872.                         \
  3873.   } while (0)
  3874.  
  3875. /*****************************************************************************
  3876.  regenerate_window_extents_only_changed
  3877.  
  3878.  This attempts to incrementally update the display structures.  It
  3879.  returns a boolean indicating success or failure.  This function is
  3880.  very similar to regenerate_window_incrementally and is in fact only
  3881.  called from that function.  However, because of the nature of the
  3882.  changes it deals with it sometimes makes different assumptions which
  3883.  can lead to success which are much more difficult to make when dealing
  3884.  with buffer changes.
  3885.  ****************************************************************************/
  3886. static int
  3887. regenerate_window_extents_only_changed (struct window *w, Bufpos startp,
  3888.                     Bufpos pointm,
  3889.                     Charcount beg_unchanged,
  3890.                     Charcount end_unchanged)
  3891. {
  3892.   struct buffer *b = XBUFFER (w->buffer);
  3893.   display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
  3894.   display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
  3895.  
  3896.   int dla_start = 0;
  3897.   int dla_end, line;
  3898.   int first_line, last_line;
  3899.   Bufpos start_pos;
  3900.   /* Don't define this in the loop where it is used because we
  3901.      definitely want its value to survive between passes. */
  3902.   prop_block_dynarr *prop = NULL;
  3903.  
  3904.   /* If we don't have any buffer change recorded but the modiff flag has
  3905.      been incremented, then fail.  I'm not sure of the exact circumstances
  3906.      under which this can happen, but I believe that it is probably a
  3907.      reasonable happening. */
  3908.   if (!point_visible (w, pointm, CURRENT_DISP)
  3909.       || XINT (w->last_modified[CURRENT_DISP]) < BUF_MODIFF (b))
  3910.     return 0;
  3911.  
  3912.   /* If the cursor is moved we attempt to update it.  If we succeed we
  3913.      go ahead and proceed with the optimization attempt. */
  3914.   if (!EQ (Fmarker_buffer (w->last_point[CURRENT_DISP]), w->buffer)
  3915.       || pointm != marker_position (w->last_point[CURRENT_DISP]))
  3916.     {
  3917.       struct frame *f = XFRAME (w->frame);
  3918.       struct device *d = XDEVICE (f->device);
  3919.       struct frame *sel_f = device_selected_frame (d);
  3920.       int success = 0;
  3921.  
  3922.       if (w->last_point_x[CURRENT_DISP] != -1
  3923.       && w->last_point_y[CURRENT_DISP] != -1)
  3924.     {
  3925.  
  3926.       if (redisplay_move_cursor (w, pointm, WINDOW_IS_TTY (w)))
  3927.         {
  3928.           /* Always regenerate the modeline in case it is
  3929.                  displaying the current line or column. */
  3930.           regenerate_modeline (w);
  3931.           success = 1;
  3932.         }
  3933.     }
  3934.       else if (w != XWINDOW (FRAME_SELECTED_WINDOW (sel_f)))
  3935.     {
  3936.       if (f->modeline_changed)
  3937.         regenerate_modeline (w);
  3938.       success = 1;
  3939.     }
  3940.  
  3941.       if (!success)
  3942.     return 0;
  3943.     }
  3944.  
  3945.   if (beg_unchanged == -1 && end_unchanged == -1)
  3946.     return 1;
  3947.  
  3948.   /* assert: There are no buffer modifications or they are all below the
  3949.      visible region.  We assume that regenerate_window_incrementally has
  3950.      not called us unless this is true.  */
  3951.  
  3952.   REGEN_INC_FIND_START_END;
  3953.  
  3954.   /* If the changed are starts before the visible area, give up. */
  3955.   if (beg_unchanged < startp)
  3956.     return 0;
  3957.  
  3958.   /* Find what display line the extent changes first affect. */
  3959.   line = dla_start;
  3960.   while (line <= dla_end)
  3961.     {
  3962.       struct display_line *dl = Dynarr_atp (cdla, line);
  3963.       Bufpos lstart = dl->bufpos + dl->offset;
  3964.       Bufpos lend = dl->end_bufpos + dl->offset;
  3965.  
  3966.       if (beg_unchanged >= lstart && beg_unchanged <= lend)
  3967.     break;
  3968.  
  3969.       line++;
  3970.     }
  3971.  
  3972.   /* If the changes are below the visible area then if point hasn't
  3973.      moved return success otherwise fail in order to be safe. */
  3974.   if (line > dla_end)
  3975.     {
  3976.       if (EQ (Fmarker_buffer (w->last_point[CURRENT_DISP]), w->buffer)
  3977.       && pointm == marker_position (w->last_point[CURRENT_DISP]))
  3978.     return 1;
  3979.       else
  3980.     return 0;
  3981.     }
  3982.  
  3983.   /* At this point we know what line the changes first affect.  We now
  3984.      begin redrawing lines as long as we are still in the affected
  3985.      region and the line's size and positioning don't change.
  3986.      Otherwise we fail.  If we fail we will have altered the desired
  3987.      structs which could lead to an assertion failure.  However, if we
  3988.      fail the next thing that is going to happen is a full regen so we
  3989.      will actually end up being safe. */
  3990.   w->last_modified[DESIRED_DISP] = make_number (BUF_MODIFF (b));
  3991.   w->last_facechange[DESIRED_DISP] = make_number (BUF_FACECHANGE (b));
  3992.   Fset_marker (w->last_start[DESIRED_DISP], make_number (startp), w->buffer);
  3993.   Fset_marker (w->last_point[DESIRED_DISP], make_number (pointm), w->buffer);
  3994.  
  3995.   first_line = last_line = line;
  3996.   while (line <= dla_end)
  3997.     {
  3998.       Bufpos old_start, old_end, new_start;
  3999.       struct display_line *cdl = Dynarr_atp (cdla, line);
  4000.       struct display_line *ddl = Dynarr_atp (ddla, line);
  4001.       struct display_block *db;
  4002.       int initial_size;
  4003.  
  4004.       assert (cdl->bufpos == ddl->bufpos);
  4005.       assert (cdl->end_bufpos == ddl->end_bufpos);
  4006.       assert (cdl->offset == ddl->offset);
  4007.  
  4008.       db = get_display_block_from_line (ddl, TEXT);
  4009.       initial_size = Dynarr_length (db->runes);
  4010.       old_start = ddl->bufpos + ddl->offset;
  4011.       old_end = ddl->end_bufpos + ddl->offset;
  4012.  
  4013.       /* If this is the first line being updated and it used
  4014.          propogation data, fail.  Otherwise we'll be okay because
  4015.          we'll have the necessary propogation data. */
  4016.       if (line == first_line && ddl->used_prop_data)
  4017.     return 0;
  4018.  
  4019.       new_start = generate_display_line (w, ddl, 0, ddl->bufpos + ddl->offset,
  4020.                      w->hscroll, &prop, DESIRED_DISP);
  4021.       ddl->offset = 0;
  4022.  
  4023.       /* #### If there is propogated stuff the fail.  We could
  4024.          probably actually deal with this if the line had propogated
  4025.          information when originally created by a full
  4026.          regeneration. */
  4027.       if (prop)
  4028.     {
  4029.       Dynarr_free (prop);
  4030.       return 0;
  4031.     }
  4032.  
  4033.       /* If any line position parameters have changed or a
  4034.          cursor has disappeared or disappeared, fail.  */
  4035.       db = get_display_block_from_line (ddl, TEXT);
  4036.       if (cdl->ypos != ddl->ypos
  4037.       || cdl->ascent != ddl->ascent
  4038.       || cdl->descent != ddl->descent
  4039.       || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1)
  4040.       || (cdl->cursor_elt == -1 && ddl->cursor_elt != -1)
  4041.       || old_start != ddl->bufpos
  4042.       || old_end != ddl->end_bufpos
  4043.       || initial_size != Dynarr_length (db->runes))
  4044.     {
  4045.       return 0;
  4046.     }
  4047.  
  4048.       if (ddl->cursor_elt != -1)
  4049.     {
  4050.       w->last_point_x[DESIRED_DISP] = ddl->cursor_elt;
  4051.       w->last_point_y[DESIRED_DISP] = line;
  4052.     }
  4053.  
  4054.       last_line = line;
  4055.  
  4056.       /* If the extent changes end on the line we just updated then
  4057.          we're done.  Otherwise go on to the next line. */
  4058.       if (end_unchanged <= ddl->end_bufpos)
  4059.     break;
  4060.       else
  4061.     line++;
  4062.     }
  4063.  
  4064.   redisplay_update_line (w, first_line, last_line, 1);
  4065.   return 1;
  4066. }
  4067.  
  4068. /*****************************************************************************
  4069.  regenerate_window_incrementally
  4070.  
  4071.  Attempt to update the display data structures based on knowledge of
  4072.  the changed region in the buffer.  Returns a boolean indicating
  4073.  success or failure.  If this function returns a failure then a
  4074.  regenerate_window _must_ be performed next in order to maintain
  4075.  invariants located here.
  4076.  ****************************************************************************/
  4077. static int
  4078. regenerate_window_incrementally (struct window *w, Bufpos startp,
  4079.                  Bufpos pointm)
  4080. {
  4081.   struct buffer *b = XBUFFER (w->buffer);
  4082.   display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
  4083.   display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
  4084.   Charcount beg_unchanged, end_unchanged;
  4085.   Charcount extent_beg_unchanged, extent_end_unchanged;
  4086.  
  4087.   int dla_start = 0;
  4088.   int dla_end, line;
  4089.   Bufpos start_pos;
  4090.  
  4091.   /* If this function is called, the current and desired structures
  4092.      had better be identical.  If they are not, then that is a bug. */
  4093.   assert (Dynarr_length (cdla) == Dynarr_length (ddla));
  4094.  
  4095.   /* We don't handle minibuffer windows yet.  The minibuffer prompt
  4096.      screws us up. */
  4097.   if (MINI_WINDOW_P (w))
  4098.     return 0;
  4099.  
  4100.   extent_beg_unchanged = BUF_EXTENT_BEGIN_UNCHANGED (b);
  4101.   extent_end_unchanged = (BUF_EXTENT_END_UNCHANGED (b) == -1
  4102.               ? -1
  4103.               : BUF_Z (b) - BUF_EXTENT_END_UNCHANGED (b));
  4104.  
  4105.   /* If nothing has changed in the buffer, then make sure point is ok
  4106.      and succeed. */
  4107.   if (BUF_BEGIN_UNCHANGED (b) == -1 && BUF_END_UNCHANGED (b) == -1)
  4108.     return regenerate_window_extents_only_changed (w, startp, pointm,
  4109.                            extent_beg_unchanged,
  4110.                            extent_end_unchanged);
  4111.  
  4112.   /* We can't deal with deleted newlines. */
  4113.   if (BUF_NEWLINE_WAS_DELETED (b))
  4114.     return 0;
  4115.  
  4116.   beg_unchanged = BUF_BEGIN_UNCHANGED (b);
  4117.   end_unchanged = (BUF_END_UNCHANGED (b) == -1
  4118.            ? -1
  4119.            : BUF_Z (b) - BUF_END_UNCHANGED (b));
  4120.  
  4121.   REGEN_INC_FIND_START_END;
  4122.  
  4123.   /* If the changed area starts before the visible area, give up. */
  4124.   if (beg_unchanged < startp)
  4125.     return 0;
  4126.  
  4127.   /* Find what display line the buffer changes first affect. */
  4128.   line = dla_start;
  4129.   while (line <= dla_end)
  4130.     {
  4131.       struct display_line *dl = Dynarr_atp (cdla, line);
  4132.       Bufpos lstart = dl->bufpos + dl->offset;
  4133.       Bufpos lend = dl->end_bufpos + dl->offset;
  4134.  
  4135.       if (beg_unchanged >= lstart && beg_unchanged <= lend)
  4136.     break;
  4137.  
  4138.       line++;
  4139.     }
  4140.  
  4141.   /* If the changes are below the visible area then if point hasn't
  4142.      moved return success otherwise fail in order to be safe. */
  4143.   if (line > dla_end)
  4144.     {
  4145.       return regenerate_window_extents_only_changed (w, startp, pointm,
  4146.                              extent_beg_unchanged,
  4147.                              extent_end_unchanged);
  4148.     }
  4149.   else
  4150.     /* At this point we know what line the changes first affect.  We
  4151.        now redraw that line.  If the changes are contained within it
  4152.        we are going to succeed and can update just that one line.
  4153.        Otherwise we fail.  If we fail we will have altered the desired
  4154.        structs which could lead to an assertion failure.  However, if
  4155.        we fail the next thing that is going to happen is a full regen
  4156.        so we will actually end up being safe. */
  4157.     {
  4158.       Bufpos new_start;
  4159.       prop_block_dynarr *prop = NULL;
  4160.       struct display_line *cdl = Dynarr_atp (cdla, line);
  4161.       struct display_line *ddl = Dynarr_atp (ddla, line);
  4162.  
  4163.       assert (cdl->bufpos == ddl->bufpos);
  4164.       assert (cdl->end_bufpos == ddl->end_bufpos);
  4165.       assert (cdl->offset == ddl->offset);
  4166.  
  4167.       /* If the last rune is already a continuation glyph, fail.
  4168.          #### We should be able to handle this better. */
  4169.       {
  4170.     struct display_block *db = get_display_block_from_line (ddl, TEXT);
  4171.     if (Dynarr_length (db->runes))
  4172.       {
  4173.         struct rune *rb =
  4174.           Dynarr_atp (db->runes, Dynarr_length (db->runes) - 1);
  4175.  
  4176.         if (rb->type == DGLYPH
  4177.         && EQ (rb->object.dglyph.glyph, Vcontinuation_glyph))
  4178.           return 0;
  4179.       }
  4180.       }
  4181.  
  4182.       /* If the line was generated using propogation data, fail. */
  4183.       if (ddl->used_prop_data)
  4184.     return 0;
  4185.  
  4186.       new_start = generate_display_line (w, ddl, 0, ddl->bufpos + ddl->offset,
  4187.                      w->hscroll, &prop, DESIRED_DISP);
  4188.       ddl->offset = 0;
  4189.  
  4190.       /* If there is propagated stuff then it is pretty much a
  4191.          guarantee that more than just the one line is affected. */
  4192.       if (prop)
  4193.     {
  4194.       Dynarr_free (prop);
  4195.       return 0;
  4196.     }
  4197.  
  4198.       /* If the last rune is now a continuation glyph, fail. */
  4199.       {
  4200.     struct display_block *db = get_display_block_from_line (ddl, TEXT);
  4201.     if (Dynarr_length (db->runes))
  4202.       {
  4203.         struct rune *rb =
  4204.           Dynarr_atp (db->runes, Dynarr_length (db->runes) - 1);
  4205.  
  4206.         if (rb->type == DGLYPH
  4207.         && EQ (rb->object.dglyph.glyph, Vcontinuation_glyph))
  4208.           return 0;
  4209.       }
  4210.       }
  4211.  
  4212.       /* If any line position parameters have changed or a
  4213.          cursor has disappeared or disappeared, fail. */
  4214.       if (cdl->ypos != ddl->ypos
  4215.       || cdl->ascent != ddl->ascent
  4216.       || cdl->descent != ddl->descent
  4217.       || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1)
  4218.       || (cdl->cursor_elt == -1 && ddl->cursor_elt != -1))
  4219.     {
  4220.       return 0;
  4221.     }
  4222.  
  4223.       /* If the changed area also ends on this line, then we may be in
  4224.          business.  Update everything and return success. */
  4225.       if (end_unchanged >= ddl->bufpos && end_unchanged <= ddl->end_bufpos)
  4226.     {
  4227.       w->last_modified[DESIRED_DISP] = make_number (BUF_MODIFF (b));
  4228.       w->last_facechange[DESIRED_DISP] = make_number (BUF_FACECHANGE (b));
  4229.       Fset_marker (w->last_start[DESIRED_DISP], make_number (startp),
  4230.                w->buffer);
  4231.       Fset_marker (w->last_point[DESIRED_DISP], make_number (pointm),
  4232.                w->buffer);
  4233.  
  4234.       if (ddl->cursor_elt != -1)
  4235.         {
  4236.           w->last_point_x[DESIRED_DISP] = ddl->cursor_elt;
  4237.           w->last_point_y[DESIRED_DISP] = line;
  4238.         }
  4239.  
  4240.       redisplay_update_line (w, line, line, 1);
  4241.       regenerate_modeline (w);
  4242.  
  4243.       /* #### For now we just flush the cache until this has been
  4244.              tested.  After that is done, this should correct the
  4245.              cache directly. */
  4246.       Dynarr_reset (w->line_start_cache);
  4247.  
  4248.       /* Adjust the extent changed boundaries to remove any
  4249.              overlap with the buffer changes since we've just
  4250.              successfully updated that area. */
  4251.       if (extent_beg_unchanged != -1
  4252.           && extent_beg_unchanged >= beg_unchanged
  4253.           && extent_beg_unchanged < end_unchanged)
  4254.         extent_beg_unchanged = end_unchanged;
  4255.  
  4256.       if (extent_end_unchanged != -1
  4257.           && extent_end_unchanged >= beg_unchanged
  4258.           && extent_end_unchanged < end_unchanged)
  4259.         extent_end_unchanged = beg_unchanged - 1;
  4260.  
  4261.       if (extent_end_unchanged <= extent_beg_unchanged)
  4262.         extent_beg_unchanged = extent_end_unchanged = -1;
  4263.  
  4264.       /* This could lead to odd results if it fails, but since the
  4265.              buffer changes update succeeded this probably will to.
  4266.              We already know that the extent changes start at or after
  4267.              the line because we checked before entering the loop. */
  4268.       if (extent_beg_unchanged != -1
  4269.           && extent_end_unchanged != -1
  4270.           && ((extent_beg_unchanged < ddl->bufpos)
  4271.           || (extent_end_unchanged > ddl->end_bufpos)))
  4272.         {
  4273.           return
  4274.         regenerate_window_extents_only_changed (w, startp, pointm,
  4275.                             extent_beg_unchanged,
  4276.                             extent_end_unchanged);
  4277.         }
  4278.       else
  4279.         return 1;
  4280.     }
  4281.     }
  4282.  
  4283.   /* Oh, well. */
  4284.   return 0;
  4285. }
  4286.  
  4287. /*****************************************************************************
  4288.  regenerate_window_point_center
  4289.  
  4290.  Given a window and a point, update the given display lines such that
  4291.  point is displayed in the middle of the window.
  4292.  ****************************************************************************/
  4293. static void
  4294. regenerate_window_point_center (struct window *w, Bufpos point, int type)
  4295. {
  4296.   Bufpos startp;
  4297.  
  4298.   startp = start_with_line_at_pixpos (w, point, window_half_pixpos (w));
  4299.   regenerate_window (w, startp, point, type);
  4300.   Fset_marker (w->start[type], make_number (startp), w->buffer);
  4301.  
  4302.   return;
  4303. }
  4304.  
  4305. /*****************************************************************************
  4306.  point_visible
  4307.  
  4308.  Given a window and a set of display lines, return a boolean indicating
  4309.  whether the given point is contained within.
  4310.  ****************************************************************************/
  4311. static int
  4312. point_visible (struct window *w, Bufpos point, int type)
  4313. {
  4314.   struct buffer *b = XBUFFER (w->buffer);
  4315.   display_line_dynarr *dla = window_display_lines (w, type);
  4316.   int first_line;
  4317.  
  4318.   if (Dynarr_length (dla) && Dynarr_atp (dla, 0)->modeline)
  4319.     first_line = 1;
  4320.   else
  4321.     first_line = 0;
  4322.  
  4323.   if (Dynarr_length (dla) > first_line)
  4324.     {
  4325.       Bufpos start, end;
  4326.       struct display_line *dl = Dynarr_atp (dla, first_line);
  4327.  
  4328.       start = dl->bufpos;
  4329.       end = BUF_Z (b) - w->window_end_pos[type] - 1;
  4330.  
  4331.       if (point >= start && point <= end)
  4332.     {
  4333.       if (!MINI_WINDOW_P (w) && scroll_on_clipped_lines)
  4334.         {
  4335.           dl = Dynarr_atp (dla, Dynarr_length (dla) - 1);
  4336.  
  4337.           if (point >= (dl->bufpos + dl->offset)
  4338.           && point <= (dl->end_bufpos + dl->offset))
  4339.         return (!dl->clip);
  4340.           else
  4341.         return 1;
  4342.         }
  4343.       else
  4344.         return 1;
  4345.     }
  4346.       else
  4347.     return 0;
  4348.     }
  4349.   else
  4350.     return 0;
  4351. }
  4352.  
  4353. /*****************************************************************************
  4354.  window_half_pixpos
  4355.  
  4356.  Return pixel position the middle of the window, not including the
  4357.  modeline and any potential horizontal scrollbar.
  4358.  ****************************************************************************/
  4359. int
  4360. window_half_pixpos (struct window *w)
  4361. {
  4362.   return (WINDOW_TEXT_TOP (w) + (WINDOW_TEXT_HEIGHT (w) >> 1));
  4363. }
  4364.  
  4365. /*****************************************************************************
  4366.  line_at_center
  4367.  
  4368.  Return the display line which is currently in the middle of the
  4369.  window W for display lines TYPE.
  4370.  ****************************************************************************/
  4371. int
  4372. line_at_center (struct window *w, int type)
  4373. {
  4374.   display_line_dynarr *dla = window_display_lines (w, type);
  4375.   int half = window_half_pixpos (w);
  4376.   int elt;
  4377.   int first_elt = (MINI_WINDOW_P (w) ? 0 : 1);
  4378.  
  4379.   for (elt = first_elt; elt < Dynarr_length (dla); elt++)
  4380.     {
  4381.       struct display_line *dl = Dynarr_atp (dla, elt);
  4382.       int line_bot = dl->ypos + dl->descent;
  4383.  
  4384.       if (line_bot > half)
  4385.     return elt;
  4386.     }
  4387.  
  4388.   /* We may not have a line at the middle if the end of the buffer is
  4389.      being displayed. */
  4390.   return -1;
  4391. }
  4392.  
  4393. /*****************************************************************************
  4394.  point_at_center
  4395.  
  4396.  Return a value for point that would place it at the beginning of the
  4397.  line which is in the middle of the window.
  4398.  ****************************************************************************/
  4399. Bufpos
  4400. point_at_center (struct window *w, int type, int regen, Bufpos start,
  4401.          Bufpos point)
  4402. {
  4403.   int line;
  4404.  
  4405.   if (regen)
  4406.     regenerate_window (w, start, point, type);
  4407.   line = line_at_center (w, type);
  4408.  
  4409.   if (line == -1)
  4410.     return BUF_ZV (XBUFFER (w->buffer));
  4411.   else
  4412.     {
  4413.       display_line_dynarr *dla = window_display_lines (w, type);
  4414.       struct display_line *dl = Dynarr_atp (dla, line);
  4415.  
  4416.       return dl->bufpos;
  4417.     }
  4418. }
  4419.  
  4420. /*****************************************************************************
  4421.  redisplay_window
  4422.  
  4423.  For a given window, ensure that the current visual representation is
  4424.  accurate.
  4425.  ****************************************************************************/
  4426. static void
  4427. redisplay_window (Lisp_Object window, int skip_selected)
  4428. {
  4429.   struct window *w = XWINDOW (window);
  4430.   struct frame *f = XFRAME (w->frame);
  4431.   struct device *d = XDEVICE (f->device);
  4432.   Lisp_Object old_buffer = w->buffer;
  4433.   struct buffer *b;
  4434.   int echo_active = 0;
  4435.   int startp = 1;
  4436.   int pointm;
  4437.   int selected;
  4438.   int skip_output = 0;
  4439.   int truncation_changed;
  4440.   int inactive_minibuffer =
  4441.     (MINI_WINDOW_P (w) && f != device_selected_frame (d));
  4442.  
  4443.   /* #### In the new world this function actually does a bunch of
  4444.      optimizations such as buffer-based scrolling, but none of that is
  4445.      implemented yet. */
  4446.  
  4447.   /* If this is a combination window, do its children; that's all.
  4448.      The selected window is always a leaf so we don't check for
  4449.      skip_selected here. */
  4450.   if (!NILP (w->vchild))
  4451.     {
  4452.       redisplay_windows (w->vchild, skip_selected);
  4453.       return;
  4454.     }
  4455.   if (!NILP (w->hchild))
  4456.     {
  4457.       redisplay_windows (w->hchild, skip_selected);
  4458.       return;
  4459.     }
  4460.  
  4461.   /* Is this window the selected window on its frame? */
  4462.   selected =
  4463.     (w == XWINDOW (FRAME_SELECTED_WINDOW (device_selected_frame (d))));
  4464.   if (skip_selected && selected)
  4465.     return;
  4466.  
  4467.   /* It is possible that the window is not fully initialized yet. */
  4468.   if (NILP (w->buffer))
  4469.     return;
  4470.  
  4471.   if (MINI_WINDOW_P (w) && echo_area_active (f))
  4472.     {
  4473.       w->buffer = Vecho_area_buffer;
  4474.       echo_active = 1;
  4475.     }
  4476.  
  4477.   b = XBUFFER (w->buffer);
  4478.  
  4479.   if (echo_active)
  4480.     pointm = 1;
  4481.   else
  4482.     {
  4483.       if (selected)
  4484.     {
  4485.       pointm = BUF_PT (b);
  4486.     }
  4487.       else
  4488.     {
  4489.       pointm = marker_position (w->pointm[CURRENT_DISP]);
  4490.  
  4491.       if (pointm < BUF_BEGV (b))
  4492.         pointm = BUF_BEGV (b);
  4493.       else if (pointm > BUF_ZV (b))
  4494.         pointm = BUF_ZV (b);
  4495.     }
  4496.     }
  4497.   Fset_marker (w->pointm[DESIRED_DISP], make_number (pointm), old_buffer);
  4498.  
  4499.   /* If the buffer has changed we have to invalid all of our face
  4500.      cache elements. */
  4501.   if ((!echo_active && b != window_display_buffer (w))
  4502.       || !Dynarr_length (w->face_cache_elements)
  4503.       || f->faces_changed)
  4504.     reset_face_cache_elements (w);
  4505.   else
  4506.     mark_face_cache_elements_as_not_updated (w);
  4507.  
  4508.   /* Ditto the glyph cache elements. */
  4509.   if ((!echo_active && b != window_display_buffer (w))
  4510.       || !Dynarr_length (w->glyph_cache_elements))
  4511.     reset_glyph_cache_elements (w);
  4512.   else
  4513.     mark_glyph_cache_elements_as_not_updated (w);
  4514.  
  4515.   /* If the marker's buffer is not the window's buffer, then we need
  4516.      to find a new starting position. */
  4517.   if (!MINI_WINDOW_P (w)
  4518.       && !EQ (Fmarker_buffer (w->start[CURRENT_DISP]), w->buffer))
  4519.     {
  4520.       regenerate_window_point_center (w, pointm, DESIRED_DISP);
  4521.  
  4522.       goto regeneration_done;
  4523.     }
  4524.  
  4525.   if (echo_active)
  4526.     startp = 1;
  4527.   else
  4528.     {
  4529.       startp = marker_position (w->start[CURRENT_DISP]);
  4530.       if (startp < BUF_BEGV (b))
  4531.     startp = BUF_BEGV (b);
  4532.       else if (startp > BUF_ZV (b))
  4533.     startp = BUF_ZV (b);
  4534.     }
  4535.   Fset_marker (w->start[DESIRED_DISP], make_number (startp), old_buffer);
  4536.  
  4537.   truncation_changed = (find_window_mirror (w)->truncate_win !=
  4538.             window_truncation_on (w));
  4539.  
  4540.   /* If w->force_start is set, then some function set w->start and we
  4541.      should display from there and change point, if necessary, to
  4542.      ensure that it is visible. */
  4543.   if (w->force_start || inactive_minibuffer)
  4544.     {
  4545.       w->force_start = 0;
  4546.       w->last_modified[DESIRED_DISP] = Qzero;
  4547.       w->last_facechange[DESIRED_DISP] = Qzero;
  4548.  
  4549.       regenerate_window (w, startp, pointm, DESIRED_DISP);
  4550.  
  4551.       if (!point_visible (w, pointm, DESIRED_DISP) && !inactive_minibuffer)
  4552.     {
  4553.       pointm = point_at_center (w, DESIRED_DISP, 0, 0, 0);
  4554.  
  4555.       if (selected)
  4556.         BUF_SET_PT (b, pointm);
  4557.  
  4558.       Fset_marker (w->pointm[DESIRED_DISP], make_number (pointm),
  4559.                old_buffer);
  4560.  
  4561.       /* #### BUFU amounts of overkil just to get the cursor
  4562.              location marked properly.  FIX ME FIX ME FIX ME */
  4563.       regenerate_window (w, startp, pointm, DESIRED_DISP);
  4564.     }
  4565.  
  4566.       goto regeneration_done;
  4567.     }
  4568.  
  4569.   /* If nothing has changed since the last redisplay, then we just
  4570.      need to make sure that point is still visible. */
  4571.   if (XINT (w->last_modified[CURRENT_DISP]) >= BUF_MODIFF (b)
  4572.       && XINT (w->last_facechange[CURRENT_DISP]) >= BUF_FACECHANGE (b)
  4573.       && pointm >= startp
  4574.       /* This check is to make sure we restore the minibuffer after a
  4575.          temporary change to the echo area. */
  4576.       && !(MINI_WINDOW_P (w) && f->buffers_changed)
  4577.       && !f->frame_changed
  4578.       && !truncation_changed)
  4579.     {
  4580.       /* Check if the cursor has actually moved. */
  4581.       if (EQ (Fmarker_buffer (w->last_point[CURRENT_DISP]), w->buffer)
  4582.       && pointm == marker_position (w->last_point[CURRENT_DISP])
  4583.       && selected
  4584.       && !w->windows_changed
  4585.       && !f->clip_changed
  4586.       && !f->extents_changed
  4587.       && !f->faces_changed
  4588.       && !f->point_changed
  4589.       && !f->windows_structure_changed)
  4590.     {
  4591.       /* If not, we're done. */
  4592.       if (f->modeline_changed)
  4593.         regenerate_modeline (w);
  4594.  
  4595.       skip_output = 1;
  4596.       goto regeneration_done;
  4597.     }
  4598.       else
  4599.     {
  4600.       /* If the new point is visible in the redisplay structures,
  4601.              then let the output update routines handle it, otherwise
  4602.              do things the hard way. */
  4603.       if (!w->windows_changed
  4604.           && !f->clip_changed
  4605.           && !f->extents_changed
  4606.           && !f->faces_changed
  4607.           && !f->windows_structure_changed)
  4608.         {
  4609.           if (point_visible (w, pointm, CURRENT_DISP)
  4610.           && w->last_point_x[CURRENT_DISP] != -1
  4611.           && w->last_point_y[CURRENT_DISP] != -1)
  4612.         {
  4613.           if (redisplay_move_cursor (w, pointm, FRAME_IS_TTY (f)))
  4614.             {
  4615.               /* Always regenerate in case it is displaying
  4616.                          the current line or column. */
  4617.               regenerate_modeline (w);
  4618.  
  4619.               skip_output = 1;
  4620.               goto regeneration_done;
  4621.             }
  4622.         }
  4623.           else if (!selected && !f->point_changed)
  4624.         {
  4625.           if (f->modeline_changed)
  4626.             regenerate_modeline (w);
  4627.  
  4628.           skip_output = 1;
  4629.           goto regeneration_done;
  4630.         }
  4631.         }
  4632.  
  4633.       /* If we weren't able to take the shortcut method, then use
  4634.              the brute force method. */
  4635.       regenerate_window (w, startp, pointm, DESIRED_DISP);
  4636.  
  4637.       if (point_visible (w, pointm, DESIRED_DISP))
  4638.         goto regeneration_done;
  4639.     }
  4640.     }
  4641.  
  4642.   /* Check if the starting point is no longer at the beginning of a
  4643.      line, in which case find a new starting point.  We also recenter
  4644.      if our start position is equal to point-max.  Otherwise we'll end
  4645.      up with a blank window. */
  4646.   else if (((w->start_at_line_beg || MINI_WINDOW_P (w))
  4647.         && !(startp == BUF_BEGV (b)
  4648.          || BUF_FETCH_CHAR (b, startp - 1) == '\n'))
  4649.        || (pointm == startp &&
  4650.            EQ (Fmarker_buffer (w->last_start[CURRENT_DISP]), w->buffer) &&
  4651.            startp < marker_position (w->last_start[CURRENT_DISP]))
  4652.        || (startp == BUF_ZV (b)))
  4653.     {
  4654.       regenerate_window_point_center (w, pointm, DESIRED_DISP);
  4655.  
  4656.       goto regeneration_done;
  4657.     }
  4658.   /* See if we can update the data structures locally based on
  4659.      knowledge of what changed in the buffer. */
  4660.   else if (!w->windows_changed
  4661.        && !f->clip_changed
  4662.        && !f->faces_changed
  4663.        && !f->windows_structure_changed
  4664.        && !f->frame_changed
  4665.        && !truncation_changed
  4666.        && pointm >= startp
  4667.        && regenerate_window_incrementally (w, startp, pointm))
  4668.     {
  4669.       if (f->modeline_changed
  4670.       || XINT (w->last_modified[CURRENT_DISP]) < BUF_MODIFF (b)
  4671.       || XINT (w->last_facechange[CURRENT_DISP]) < BUF_FACECHANGE (b))
  4672.     regenerate_modeline (w);
  4673.  
  4674.       skip_output = 1;
  4675.       goto regeneration_done;
  4676.     }
  4677.   /* #### This is where a check for structure based scrolling would go. */
  4678.   /* If all else fails, try just regenerating and see what happens. */
  4679.   else
  4680.     {
  4681.       regenerate_window (w, startp, pointm, DESIRED_DISP);
  4682.  
  4683.       if (point_visible (w, pointm, DESIRED_DISP))
  4684.     goto regeneration_done;
  4685.     }
  4686.  
  4687.   /* We still haven't gotten the window regenerated with point
  4688.      visible.  Next we try scrolling a little and see if point comes
  4689.      back onto the screen. */
  4690.   if (scroll_step)
  4691.     {
  4692.       Bufpos bufpos;
  4693.  
  4694.       bufpos = vmotion (w, startp,
  4695.             (pointm < startp) ? -scroll_step : scroll_step, 0);
  4696.       regenerate_window (w, bufpos, pointm, DESIRED_DISP);
  4697.  
  4698.       if (point_visible (w, pointm, DESIRED_DISP))
  4699.     goto regeneration_done;
  4700.     }
  4701.  
  4702.   /* We still haven't managed to get the screen drawn with point on
  4703.      the screen, so just center it and be done with it. */
  4704.   regenerate_window_point_center (w, pointm, DESIRED_DISP);
  4705.  
  4706.  
  4707. regeneration_done:
  4708.  
  4709.   /* If the window's frame is changed then reset the current display
  4710.      lines in order to force a full repaint. */
  4711.   if (f->frame_changed)
  4712.     {
  4713.       display_line_dynarr *cla = window_display_lines (w, CURRENT_DISP);
  4714.  
  4715.       Dynarr_reset (cla);
  4716.     }
  4717.  
  4718.   /* Must do this before calling redisplay_output_window because it
  4719.      sets some markers on the window. */
  4720.   if (MINI_WINDOW_P (w) && echo_area_active (f))
  4721.     w->buffer = old_buffer;
  4722.  
  4723.   /* These also have to be set before calling redisplay_output_window
  4724.      since it sets the CURRENT_DISP values based on them. */
  4725.   w->last_modified[DESIRED_DISP] = make_number (BUF_MODIFF (b));
  4726.   w->last_facechange[DESIRED_DISP] = make_number (BUF_FACECHANGE (b));
  4727.   Fset_marker (w->last_start[DESIRED_DISP], make_number (startp), w->buffer);
  4728.   Fset_marker (w->last_point[DESIRED_DISP], make_number (pointm), w->buffer);
  4729.  
  4730.   if (!skip_output)
  4731.     {
  4732.       Bufpos start = marker_position (w->start[DESIRED_DISP]);
  4733.       Bufpos end = (w->window_end_pos[DESIRED_DISP] == -1
  4734.             ? BUF_ZV (b)
  4735.             : BUF_Z (b) - w->window_end_pos[DESIRED_DISP] - 1);
  4736.  
  4737.       update_line_start_cache (w, start, end, pointm, 1);
  4738.       redisplay_output_window (w);
  4739.     }
  4740.  
  4741.   /* #### This should be dependent on face changes and will need to be
  4742.      somewhere else once tty updates occur on a per-frame basis. */
  4743.   mark_face_cache_elements_as_clean (w);
  4744.  
  4745.   w->windows_changed = 0;
  4746. }
  4747.  
  4748. /*****************************************************************************
  4749.  reset_buffer_changes
  4750.  reset_buffer_changes_mapfun -- internal
  4751.  
  4752.  Call buffer_reset_changes for all buffers present in any window
  4753.  currently visible in all frames on all devices.
  4754.  #### There has to be a better way to do this.
  4755.  ****************************************************************************/
  4756.  
  4757. static int
  4758. reset_buffer_changes_mapfun (struct window *w, void *ignored_closure)
  4759. {
  4760.   buffer_reset_changes (XBUFFER (w->buffer));
  4761.   return 0;
  4762. }
  4763.  
  4764. static void
  4765. reset_buffer_changes (void)
  4766. {
  4767.   Lisp_Object dev, frm;
  4768.   DEVICE_AND_FRAME_LOOP (dev, frm)
  4769.     {
  4770.       struct frame *f = XFRAME (XCAR (frm));
  4771.  
  4772.       if (FRAME_VISIBLE_P (f))
  4773.     map_windows (f, reset_buffer_changes_mapfun, 0);
  4774.     }
  4775. }
  4776.  
  4777. /*****************************************************************************
  4778.  redisplay_windows
  4779.  
  4780.  Ensure that all windows underneath the given window in the window
  4781.  hierarchy are correctly displayed.
  4782.  ****************************************************************************/
  4783. static void
  4784. redisplay_windows (Lisp_Object window, int skip_selected)
  4785. {
  4786.   for (; !NILP (window) ; window = XWINDOW (window)->next)
  4787.     {
  4788.       redisplay_window (window, skip_selected);
  4789.     }
  4790. }
  4791.  
  4792. /*****************************************************************************
  4793.  redisplay_frame
  4794.  
  4795.  Ensure that all windows on the given frame are correctly displayed.
  4796.  ****************************************************************************/
  4797. static int
  4798. redisplay_frame (struct frame *f)
  4799. {
  4800.   struct device *d = XDEVICE (f->device);
  4801. #if 0 /* The preemption check itself takes a lot of time,
  4802.      so don't do it here */
  4803.   int preempted;
  4804.  
  4805.   REDISPLAY_PREEMPTION_CHECK;
  4806.   if (preempted)
  4807.     return 1;
  4808. #endif
  4809.  
  4810.   /* Before we put a hold on frame size changes, attempt to process
  4811.      any which are already pending. */
  4812.   if (f->size_change_pending)
  4813.     change_frame_size (f, f->new_height, f->new_width, 1, 0);
  4814.  
  4815.   /* The menubar and toolbar updates must be done before
  4816.      hold_frame_size_changes is called and we are officially
  4817.      'in_display'.  They may eval lisp code which may call Fsignal.
  4818.      If in_display is set Fsignal will abort. */
  4819.  
  4820.   /* Update the menubar.  It is done first since it could change
  4821.      the menubar's visibility.  This way we avoid having flashing
  4822.      caused by an Expose event generated by the visibility change
  4823.      being handled. */
  4824.   update_frame_menubars (f);
  4825.  
  4826.   /* Update the toolbars. */
  4827.   update_frame_toolbars (f);
  4828.  
  4829.   /* We do not allow changes in the frame size to be processed
  4830.      while redisplay is working. */
  4831.   /* #### If a change does occur we should probably actually be
  4832.      preempting redisplay. */
  4833.   hold_frame_size_changes ();
  4834.  
  4835.   /* If we clear the frame we have to force its contents to be redrawn. */
  4836.   if (f->clear)
  4837.     f->frame_changed = 1;
  4838.  
  4839.   /* Erase the frame before outputing its contents. */
  4840.   if (f->clear)
  4841.     DEVMETH (d, clear_frame, (f));
  4842.  
  4843.   /* Do the selected window first. */
  4844.   redisplay_window (FRAME_SELECTED_WINDOW (f), 0);
  4845.  
  4846.   /* Then do the rest. */
  4847.   redisplay_windows (f->root_window, 1);
  4848.  
  4849.   /* We now call the output_end routine for tty frames.  We delay
  4850.      doing so in order to avoid cursor flicker.  So much for 100%
  4851.      encapsulation. */
  4852.   if (FRAME_IS_TTY (f))
  4853.     DEVMETH (d, output_end, (d));
  4854.  
  4855.   /* #### We should make this conditional. */
  4856.   update_frame_title (f);
  4857.  
  4858.   f->buffers_changed = 0;
  4859.   f->clip_changed = 0;
  4860.   f->extents_changed = 0;
  4861.   f->faces_changed = 0;
  4862.   f->frame_changed = 0;
  4863.   f->menubar_changed = 0;
  4864.   f->modeline_changed = 0;
  4865.   f->point_changed = 0;
  4866.   f->toolbar_changed = 0;
  4867.   f->windows_changed = 0;
  4868.   f->windows_structure_changed = 0;
  4869.   f->window_face_cache_reset = 0;
  4870.  
  4871.   f->clear = 0;
  4872.  
  4873.   if (!f->size_change_pending)
  4874.     f->size_changed = 0;
  4875.  
  4876.   /* Allow frame size changes to occur again. */
  4877.   unhold_frame_size_changes (f);
  4878.  
  4879.   return 0;
  4880. }
  4881.  
  4882. /*****************************************************************************
  4883.  redisplay_device
  4884.  
  4885.  Ensure that all frames on the given device are correctly displayed.
  4886.  ****************************************************************************/
  4887. static int
  4888. redisplay_device (struct device *d)
  4889. {
  4890.   Lisp_Object frm;
  4891.   int preempted = 0;
  4892.   int size_change_failed = 0;
  4893.  
  4894.   if (DEVICE_IS_STREAM (d)) /* nothing to do */
  4895.     return 0;
  4896.  
  4897.   /* It is possible that redisplay has been called before the
  4898.      device is fully initialized.  If so then continue with the
  4899.      next device. */
  4900.   if (NILP (DEVICE_SELECTED_FRAME (d)))
  4901.     return 0;
  4902.  
  4903.   REDISPLAY_PREEMPTION_CHECK;
  4904.   if (preempted)
  4905.     return 1;
  4906.  
  4907.   /* Always do the selected frame first. */
  4908.   frm = DEVICE_SELECTED_FRAME (d);
  4909.   if (FRAME_VISIBLE_P (XFRAME (frm)))
  4910.     {
  4911.       struct frame *f = XFRAME (frm);
  4912.  
  4913.       if (f->buffers_changed || f->clip_changed || f->extents_changed
  4914.       || f->faces_changed || f->frame_changed || f->menubar_changed
  4915.       || f->modeline_changed || f->point_changed || f->size_changed
  4916.       || f->toolbar_changed || f->windows_changed
  4917.       || f->windows_structure_changed)
  4918.     {
  4919.       preempted = redisplay_frame (f);
  4920.     }
  4921.  
  4922.       if (preempted)
  4923.     return 1;
  4924.  
  4925.       /* If the frame redisplay did not get preempted, then this flag
  4926.          should have gotten set to 0.  It might be possible for that
  4927.          not to happen if a size change event were to occur at an odd
  4928.          time.  To make sure we don't miss anything we simply don't
  4929.          reset the top level flags until the condition ends up being
  4930.          in the right state. */
  4931.       if (f->size_changed)
  4932.     size_change_failed = 1;
  4933.     }
  4934.  
  4935.   FRAME_LOOP (frm, d)
  4936.     {
  4937.       struct frame *f = XFRAME (XCAR (frm));
  4938.  
  4939.       if (FRAME_VISIBLE_P (f) && f != XFRAME (DEVICE_SELECTED_FRAME (d)))
  4940.     {
  4941.       if (f->buffers_changed || f->clip_changed || f->extents_changed
  4942.           || f->faces_changed || f->frame_changed || f->menubar_changed
  4943.           || f->modeline_changed || f->point_changed || f->size_changed
  4944.           || f->toolbar_changed || f->windows_changed ||
  4945.           f->windows_structure_changed)
  4946.         {
  4947.           preempted = redisplay_frame (f);
  4948.         }
  4949.  
  4950.       if (preempted)
  4951.         return 1;
  4952.  
  4953.       if (f->size_change_pending)
  4954.         size_change_failed = 1;
  4955.     }
  4956.     }
  4957.  
  4958.   /* If we get here then we redisplayed all of our frames without
  4959.      getting preempted so mark ourselves as clean. */
  4960.   d->buffers_changed = 0;
  4961.   d->clip_changed = 0;
  4962.   d->extents_changed = 0;
  4963.   d->faces_changed = 0;
  4964.   d->frame_changed = 0;
  4965.   d->menubar_changed = 0;
  4966.   d->modeline_changed = 0;
  4967.   d->point_changed = 0;
  4968.   d->toolbar_changed = 0;
  4969.   d->windows_changed = 0;
  4970.   d->windows_structure_changed = 0;
  4971.  
  4972.   if (!size_change_failed)
  4973.     d->size_changed = 0;
  4974.  
  4975.   return 0;
  4976. }
  4977.  
  4978. /*****************************************************************************
  4979.  redisplay
  4980.  
  4981.  Ensure that all windows on all frames on all devices are displaying
  4982.  the current contents of their respective buffers.
  4983.  ****************************************************************************/
  4984. static void
  4985. redisplay_without_hooks (void)
  4986. {
  4987.   Lisp_Object dev;
  4988.   int size_change_failed = 0;
  4989.  
  4990.   if (asynch_device_change_pending)
  4991.     handle_asynch_device_change ();
  4992.  
  4993.   if (!buffers_changed && !clip_changed && !extents_changed && !faces_changed
  4994.       && !frame_changed && !menubar_changed && !modeline_changed
  4995.       && !point_changed && !size_changed && !toolbar_changed
  4996.       && !windows_changed && !windows_structure_changed && !disable_preemption
  4997.       && preemption_count < max_preempts)
  4998.     return;
  4999.  
  5000.   DEVICE_LOOP (dev)
  5001.     {
  5002.       struct device *d = XDEVICE (XCAR (dev));
  5003.       int preempted;
  5004.  
  5005.       if (d->buffers_changed || d->clip_changed || d->extents_changed
  5006.       || d->faces_changed || d->frame_changed || d->menubar_changed
  5007.       || d->modeline_changed || d->point_changed || d->size_changed
  5008.       || d->toolbar_changed || d->windows_changed
  5009.       || d->windows_structure_changed)
  5010.     {
  5011.       preempted = redisplay_device (d);
  5012.  
  5013.       if (preempted)
  5014.         {
  5015.           preemption_count++;
  5016.           RESET_CHANGED_SET_FLAGS;
  5017.           return;
  5018.         }
  5019.  
  5020.       /* See comment in redisplay_device. */
  5021.       if (d->size_changed)
  5022.         size_change_failed = 1;
  5023.     }
  5024.     }
  5025.   preemption_count = 0;
  5026.  
  5027.   /* Mark redisplay as accurate */
  5028.   buffers_changed = 0;
  5029.   clip_changed = 0;
  5030.   extents_changed = 0;
  5031.   frame_changed = 0;
  5032.   menubar_changed = 0;
  5033.   modeline_changed = 0;
  5034.   point_changed = 0;
  5035.   toolbar_changed = 0;
  5036.   windows_changed = 0;
  5037.   windows_structure_changed = 0;
  5038.   RESET_CHANGED_SET_FLAGS;
  5039.  
  5040.   if (faces_changed)
  5041.     {
  5042.       mark_all_faces_as_clean ();
  5043.       faces_changed = 0;
  5044.     }
  5045.  
  5046.   if (!size_change_failed)
  5047.     size_changed = 0;
  5048.  
  5049.   reset_buffer_changes ();
  5050. }
  5051.  
  5052. void
  5053. redisplay (void)
  5054. {
  5055.   if (last_display_warning_tick != display_warning_tick &&
  5056.       !inhibit_warning_display)
  5057.     {
  5058.       /* If an error occurs during this function, oh well.
  5059.          If we report another warning, we could get stuck in an
  5060.      infinite loop reporting warnings. */
  5061.       call0_trapping_errors (0, Qdisplay_warning_buffer);
  5062.       last_display_warning_tick = display_warning_tick;
  5063.     }
  5064.   /* The run_hook_trapping_errors functions are smart enough not
  5065.      to do any evalling if the hook function is empty, so there
  5066.      should not be any significant time loss.  All places in the
  5067.      C code that call redisplay() are prepared to handle GCing,
  5068.      so we should be OK. */
  5069. #if 0
  5070.   run_hook_trapping_errors ("Error in pre-redisplay-hook",
  5071.                 Qpre_redisplay_hook);
  5072. #endif
  5073.  
  5074.   redisplay_without_hooks ();
  5075.  
  5076. #if 0
  5077.   run_hook_trapping_errors ("Error in post-redisplay-hook",
  5078.                 Qpost_redisplay_hook);
  5079. #endif
  5080. }
  5081.  
  5082. /*****************************************************************************
  5083.  redisplay_echo_area
  5084.  
  5085.  Ensure that all minibuffers are correctly showing the echo area.
  5086.  ****************************************************************************/
  5087.  
  5088. DEFUN ("redisplay-echo-area", Fredisplay_echo_area, Sredisplay_echo_area,
  5089.        0, 0, 0,
  5090.        "Ensure that all minibuffers are correctly showing the echo area.")
  5091.      ()
  5092. {
  5093.   Lisp_Object dev;
  5094.  
  5095.   DEVICE_LOOP (dev)
  5096.     {
  5097.       struct device *d = XDEVICE (XCAR (dev));
  5098.       Lisp_Object frm;
  5099.  
  5100.       FRAME_LOOP (frm, d)
  5101.     {
  5102.       struct frame *f = XFRAME (XCAR (frm));
  5103.  
  5104.       if (FRAME_VISIBLE_P (f))
  5105.         {
  5106.           redisplay_window (FRAME_MINIBUF_WINDOW (f), 0);
  5107.         }
  5108.     }
  5109.  
  5110.       /* We now call the output_end routine for tty frames.  We delay
  5111.      doing so in order to avoid cursor flicker.  So much for 100%
  5112.      encapsulation. */
  5113.       if (DEVICE_IS_TTY (d))
  5114.     DEVMETH (d, output_end, (d));
  5115.     }
  5116.  
  5117.   return Qnil;
  5118. }
  5119.  
  5120. /*****************************************************************************
  5121.  window_line_number
  5122.  
  5123.  Inefficiently determine the line number of the line point is on and
  5124.  return it as a string.  Always do this regardless of whether
  5125.  line_number_mode is true.
  5126.  ****************************************************************************/
  5127. static char window_line_number_buf[100];
  5128. static char *
  5129. window_line_number (struct window *w, int type)
  5130. {
  5131.   struct device *d = XDEVICE (XFRAME (w->frame)->device);
  5132.   struct buffer *b = XBUFFER (w->buffer);
  5133.   Bufpos end =
  5134.     ((w == XWINDOW (FRAME_SELECTED_WINDOW (device_selected_frame (d))))
  5135.      ? BUF_PT (b)
  5136.      : marker_position (w->pointm[type]));
  5137.   int lots = 999999999;
  5138.   int shortage, line;
  5139.  
  5140.   scan_buffer (b, '\n', end, 0, -lots, &shortage, 0);
  5141.   line = lots - shortage + 1;
  5142.  
  5143.   sprintf (window_line_number_buf, "%d", line);
  5144.  
  5145.   return (window_line_number_buf);
  5146. }
  5147.  
  5148. /*****************************************************************************
  5149.  decode_mode_spec
  5150.  
  5151.  Given a character representing an object in a modeline specification,
  5152.  return a string (stored into the global array `mode_spec') with the
  5153.  information that object represents.
  5154.  
  5155.  This function is largely unchanged from previous versions of the
  5156.  redisplay engine.
  5157.  ****************************************************************************/
  5158. static void
  5159. decode_mode_spec (struct window *w, Emchar spec, int type)
  5160. {
  5161.   Lisp_Object obj = Qnil;
  5162.   char *str = NULL;
  5163.   struct buffer *b = XBUFFER (w->buffer);
  5164.  
  5165.   Dynarr_reset (mode_spec);
  5166.  
  5167.   switch (spec)
  5168.     {
  5169.       /* print buffer name */
  5170.     case 'b':
  5171.       obj = b->name;
  5172.       break;
  5173.  
  5174.       /* print visited file name */
  5175.     case 'f':
  5176.       obj = b->filename;
  5177.       break;
  5178.  
  5179.       /* print the current column */
  5180.     case 'c':
  5181.       {
  5182.     int col = current_column (b);
  5183.     int temp = col;
  5184.     int size = 2;
  5185.     char *buf;
  5186.  
  5187.     while (temp >= 10)
  5188.       {
  5189.         temp /= 10;
  5190.         size++;
  5191.       }
  5192.  
  5193.     buf = (char *) alloca (size * sizeof (char));
  5194.     sprintf (buf, "%d", col);
  5195.  
  5196.     Dynarr_add_many (mode_spec, (Bufbyte *) buf, strlen (buf));
  5197.  
  5198.     goto decode_mode_spec_done;
  5199.       }
  5200.       break;
  5201.  
  5202.       /* print the current line number */
  5203.     case 'l':
  5204.       str = window_line_number (w, type);
  5205.       break;
  5206.  
  5207.       /* print value of mode-name (obsolete) */
  5208.     case 'm':
  5209.       obj = b->mode_name;
  5210.       break;
  5211.  
  5212.       /* print Narrow if appropriate */
  5213.     case 'n':
  5214.       if (BUF_BEGV (b) > BUF_BEG (b)
  5215.       || BUF_ZV (b) < BUF_Z (b))
  5216.     str = " Narrow";
  5217.       break;
  5218.  
  5219.       /* print %, * or hyphen, if buffer is read-only, modified or neither */
  5220.     case '*':
  5221.       str = (!NILP (b->read_only)
  5222.          ? "%"
  5223.          : ((BUF_MODIFF (b) > b->save_modified)
  5224.         ? "*"
  5225.         : "-"));
  5226.       break;
  5227.  
  5228.       /* print * or hyphen -- XEmacs change to allow a buffer to be
  5229.          read-only but still indicate whether it is modified. */
  5230.     case '+':
  5231.       str = ((BUF_MODIFF (b) > b->save_modified)
  5232.          ? "*"
  5233.          : (!NILP (b->read_only)
  5234.         ? "%"
  5235.         : "-"));
  5236.       break;
  5237.  
  5238.       /* #### defined in 19.29 decode_mode_spec, but not in
  5239.          modeline-format doc string. */
  5240.       /* This differs from %* in that it ignores read-only-ness. */
  5241.     case '&':
  5242.       str = ((BUF_MODIFF (b) > b->save_modified)
  5243.          ? "*"
  5244.          : "-");
  5245.       break;
  5246.  
  5247.       /* print process status */
  5248.     case 's':
  5249.       obj = Fget_buffer_process (w->buffer);
  5250.       if (NILP (obj))
  5251.     str = GETTEXT ("no process");
  5252.       else
  5253.     obj = Fsymbol_name (Fprocess_status (obj));
  5254.       break;
  5255.  
  5256.       /* print name of selected frame (only meaningful under X Windows) */
  5257.     case 'S':
  5258.       obj = XFRAME (w->frame)->name;
  5259.       break;
  5260.  
  5261.       /* indicate TEXT or BINARY */
  5262.     case 't':
  5263. #ifdef MSDOS
  5264.       str = NILP (b->buffer_file_type) ? "T" : "B";
  5265. #else /* not MSDOS */
  5266.       str = "T";
  5267. #endif /* not MSDOS */
  5268.  
  5269.       /* print percent of buffer above top of window, or Top, Bot or All */
  5270.     case 'p':
  5271.     {
  5272.       Bufpos pos = marker_position (w->start[type]);
  5273.       Charcount total = BUF_ZV (b) - BUF_BEGV (b);
  5274.  
  5275.       /* This had better be while the desired lines are being done. */
  5276.       if (w->window_end_pos[type] <= BUF_Z (b) - BUF_ZV (b))
  5277.     {
  5278.       if (pos <= BUF_BEGV (b))
  5279.         str = "All";
  5280.       else
  5281.         str = "Bottom";
  5282.     }
  5283.       else if (pos <= BUF_BEGV (b))
  5284.     str = "Top";
  5285.       else
  5286.     {
  5287.       /* This hard limit is ok since the string it will hold has a
  5288.              fixed maximum length of 3.  But just to be safe... */
  5289.       char buf[10];
  5290.  
  5291.       total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total;
  5292.  
  5293.       /* We can't normally display a 3-digit number, so get us a
  5294.              2-digit number that is close. */
  5295.       if (total == 100)
  5296.         total = 99;
  5297.  
  5298.       sprintf (buf, "%2d%%", total);
  5299.       Dynarr_add_many (mode_spec, (Bufbyte *) buf, strlen (buf));
  5300.  
  5301.       goto decode_mode_spec_done;
  5302.     }
  5303.       break;
  5304.     }
  5305.  
  5306.     /* print percent of buffer above bottom of window, perhaps plus
  5307.        Top, or print Bottom or All */
  5308.     case 'P':
  5309.     {
  5310.       Bufpos toppos = marker_position (w->start[type]);
  5311.       Bufpos botpos = BUF_Z (b) - w->window_end_pos[type];
  5312.       Charcount total = BUF_ZV (b) - BUF_BEGV (b);
  5313.  
  5314.       if (botpos >= BUF_ZV (b))
  5315.     {
  5316.       if (toppos <= BUF_BEGV (b))
  5317.         str = "All";
  5318.       else
  5319.         str = "Bottom";
  5320.     }
  5321.       else
  5322.     {
  5323.       /* This hard limit is ok since the string it will hold has a
  5324.              fixed maximum length of around 6.  But just to be safe... */
  5325.       char buf[10];
  5326.  
  5327.       total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total;
  5328.  
  5329.       /* We can't normally display a 3-digit number, so get us a
  5330.              2-digit number that is close. */
  5331.       if (total == 100)
  5332.         total = 99;
  5333.  
  5334.       if (toppos <= BUF_BEGV (b))
  5335.         sprintf (buf, "Top%2d%%", total);
  5336.       else
  5337.         sprintf (buf, "%2d%%", total);
  5338.  
  5339.       Dynarr_add_many (mode_spec, (Bufbyte *) buf, strlen (buf));
  5340.  
  5341.       goto decode_mode_spec_done;
  5342.     }
  5343.       break;
  5344.     }
  5345.  
  5346.     /* print % */
  5347.     case '%':
  5348.       str = "%";
  5349.       break;
  5350.  
  5351.       /* print one [ for each recursive editing level. */
  5352.     case '[':
  5353.     {
  5354.       int i;
  5355.  
  5356.       if (command_loop_level > 5)
  5357.     {
  5358.       str = "[[[... ";
  5359.       break;
  5360.     }
  5361.  
  5362.       for (i = 0; i < command_loop_level; i++)
  5363.     Dynarr_add (mode_spec, '[');
  5364.  
  5365.       goto decode_mode_spec_done;
  5366.     }
  5367.  
  5368.     /* print one ] for each recursive editing level. */
  5369.     case ']':
  5370.     {
  5371.       int i;
  5372.  
  5373.       if (command_loop_level > 5)
  5374.     {
  5375.       str = "...]]]";
  5376.       break;
  5377.     }
  5378.  
  5379.       for (i = 0; i < command_loop_level; i++)
  5380.     Dynarr_add (mode_spec, ']');
  5381.  
  5382.       goto decode_mode_spec_done;
  5383.     }
  5384.  
  5385.     /* print infinitely many dashes -- handle at top level now */
  5386.     case '-':
  5387.       break;
  5388.  
  5389.     }
  5390.  
  5391.   if (STRINGP (obj))
  5392.     Dynarr_add_many (mode_spec, string_data (XSTRING (obj)),
  5393.              string_length (XSTRING (obj)));
  5394.   else if (str)
  5395.     Dynarr_add_many (mode_spec, (Bufbyte *) str, strlen (str));
  5396.  
  5397. decode_mode_spec_done:
  5398.   Dynarr_add (mode_spec, '\0');
  5399. }
  5400.  
  5401. /*****************************************************************************
  5402.  free_display_line
  5403.  
  5404.  Given a display line, free all if its data structures.
  5405.  ****************************************************************************/
  5406. static void
  5407. free_display_line (struct display_line *dl)
  5408. {
  5409.   int block;
  5410.  
  5411.   if (dl->display_blocks)
  5412.     {
  5413.       for (block = 0; block < Dynarr_largest (dl->display_blocks); block++)
  5414.     {
  5415.       struct display_block *db = Dynarr_atp (dl->display_blocks, block);
  5416.  
  5417.       Dynarr_free (db->runes);
  5418.     }
  5419.  
  5420.       Dynarr_free (dl->display_blocks);
  5421.       dl->display_blocks = 0;
  5422.     }
  5423.  
  5424.   if (dl->left_glyphs)
  5425.     {
  5426.       Dynarr_free (dl->left_glyphs);
  5427.       dl->left_glyphs = 0;
  5428.     }
  5429.  
  5430.   if (dl->right_glyphs)
  5431.     {
  5432.       Dynarr_free (dl->right_glyphs);
  5433.       dl->right_glyphs = 0;
  5434.     }
  5435. }
  5436.  
  5437.  
  5438. /*****************************************************************************
  5439.  free_display_lines
  5440.  
  5441.  Given an array of display lines, free them and all data structures
  5442.  contained within them.
  5443.  ****************************************************************************/
  5444. static void
  5445. free_display_lines (display_line_dynarr *dla)
  5446. {
  5447.   int line;
  5448.  
  5449.   for (line = 0; line < Dynarr_largest (dla); line++)
  5450.     {
  5451.       free_display_line (Dynarr_atp (dla, line));
  5452.     }
  5453.  
  5454.   Dynarr_free (dla);
  5455. }
  5456.  
  5457. /*****************************************************************************
  5458.  free_display_structs
  5459.  
  5460.  Call internal free routine for each set of display lines.
  5461.  ****************************************************************************/
  5462. void
  5463. free_display_structs (struct window_mirror *mir)
  5464. {
  5465.   if (mir->current_display_lines)
  5466.     {
  5467.       free_display_lines (mir->current_display_lines);
  5468.       mir->current_display_lines = 0;
  5469.     }
  5470.  
  5471.   if (mir->desired_display_lines)
  5472.     {
  5473.       free_display_lines (mir->desired_display_lines);
  5474.       mir->desired_display_lines = 0;
  5475.     }
  5476.  
  5477.   if (mir->cmotion_display_lines)
  5478.     {
  5479.       free_display_lines (mir->cmotion_display_lines);
  5480.       mir->cmotion_display_lines = 0;
  5481.     }
  5482. }
  5483.  
  5484.  
  5485. static void
  5486. mark_redisplay_structs (display_line_dynarr *dla,
  5487.             void (*markobj) (Lisp_Object))
  5488. {
  5489.   int line;
  5490.  
  5491.   for (line = 0; line < Dynarr_length (dla); line++)
  5492.     {
  5493.       int block, loop;
  5494.       struct display_line *dl = Dynarr_atp (dla, line);
  5495.  
  5496.       for (block = 0; block < Dynarr_length (dl->display_blocks); block++)
  5497.     {
  5498.       int rune;
  5499.       struct display_block *db = Dynarr_atp (dl->display_blocks, block);
  5500.  
  5501.       for (rune = 0; rune < Dynarr_length (db->runes); rune++)
  5502.         {
  5503.           struct rune *rb = Dynarr_atp (db->runes, rune);
  5504.  
  5505.           if (!NILP (rb->extent))
  5506.         ((markobj) (rb->extent));
  5507.           if (rb->type == DGLYPH && !NILP (rb->object.dglyph.glyph))
  5508.         ((markobj) (rb->object.dglyph.glyph));
  5509.         }
  5510.     }
  5511.  
  5512.       for (loop = 0; loop < 2; loop++)
  5513.     {
  5514.       glyph_block_dynarr *gba = (loop
  5515.                      ? dl->right_glyphs
  5516.                      : dl->left_glyphs);
  5517.  
  5518.       if (gba != NULL)
  5519.         {
  5520.           for (block = 0; block < Dynarr_length (gba); block++)
  5521.         {
  5522.           struct glyph_block *gb = Dynarr_atp (gba, block);
  5523.  
  5524.           if (!NILP (gb->glyph))
  5525.             ((markobj) (gb->glyph));
  5526.           if (!NILP (gb->extent))
  5527.             ((markobj) (gb->extent));
  5528.         }
  5529.         }
  5530.     }
  5531.     }
  5532. }
  5533.  
  5534. static void
  5535. mark_window_mirror (struct window_mirror *mir, void (*markobj)(Lisp_Object))
  5536. {
  5537.   mark_redisplay_structs (mir->current_display_lines, markobj);
  5538.   mark_redisplay_structs (mir->desired_display_lines, markobj);
  5539.   mark_redisplay_structs (mir->cmotion_display_lines, markobj);
  5540.  
  5541.   if (mir->next)
  5542.     mark_window_mirror (mir->next, markobj);
  5543.  
  5544.   if (mir->hchild)
  5545.     mark_window_mirror (mir->hchild, markobj);
  5546.   else if (mir->vchild)
  5547.     mark_window_mirror (mir->vchild, markobj);
  5548. }
  5549.  
  5550. void
  5551. mark_redisplay (void (*markobj)(Lisp_Object))
  5552. {
  5553.   Lisp_Object device;
  5554.  
  5555.   DEVICE_LOOP (device)
  5556.     {
  5557.       Lisp_Object rest;
  5558.  
  5559.       if (!gc_record_type_p (XCAR (device), lrecord_device))
  5560.     abort ();    /* ASSERT - all Vdevice_list entries must be devices */
  5561.  
  5562.       for (rest = DEVICE_FRAME_LIST (XDEVICE (XCAR (device)));
  5563.        !NILP (rest);
  5564.        rest = XCDR (rest))
  5565.     {
  5566.       Lisp_Object frame = XCAR (rest);
  5567.       struct frame *f;
  5568.       if (! gc_record_type_p (frame, lrecord_frame))
  5569.         abort ();
  5570.       f = XFRAME (XCAR (rest));
  5571.       update_frame_window_mirror (f);
  5572.       mark_window_mirror (f->root_mirror, markobj);
  5573.     }
  5574.     }
  5575. }
  5576.  
  5577. /*****************************************************************************
  5578.  Line Start Cache Description and Rationale
  5579.  
  5580.  The traditional scrolling code in Emacs breaks in a variable height world.
  5581.  It depends on the key assumption that the number of lines that can be
  5582.  displayed at any given time is fixed.  This led to a complete separation
  5583.  of the scrolling code from the redisplay code.  In order to fully support
  5584.  variable height lines, the scrolling code must actually be tightly
  5585.  integrated with redisplay.  Only redisplay can determine how many lines
  5586.  will be displayed on a screen for any given starting point.
  5587.  
  5588.  What is ideally wanted is a complete list of the starting buffer position
  5589.  for every possible display line of a buffer along with the height of that
  5590.  display line.  Maintaining such a full list would be very expensive.  We
  5591.  settle for having it include information for all areas which we happen to
  5592.  generate anyhow (i.e. the region currently being displayed) and for those
  5593.  areas we need to work with.
  5594.  
  5595.  In order to ensure that the cache accurately represents what redisplay
  5596.  would actually show, it is necessary to invalidate it in many situations.
  5597.  If the buffer changes, the starting positions may no longer be correct.
  5598.  If a face or an extent has changed then the line heights may have altered.
  5599.  These events happen frequently enough that the cache can end up being
  5600.  constantly disabled.  With this potentially constant invalidation when is
  5601.  the cache ever useful?
  5602.  
  5603.  Even if the cache is invalidated before every single usage, it is
  5604.  necessary.  Scrolling often requires knowledge about display lines which
  5605.  are actually above or below the visible region.  The cache provides a
  5606.  convenient light-weight method of storing this information for multiple
  5607.  display regions.  This knowledge is necessary for the scrolling code to
  5608.  always obey the First Golden Rule of Redisplay.
  5609.  
  5610.  If the cache already contains all of the information that the scrolling
  5611.  routines happen to need so that it doesn't have to go generate it, then we
  5612.  are able to obey the Third Golden Rule of Redisplay.  The first thing we
  5613.  do to help out the cache is to always add the displayed region.  This
  5614.  region had to be generated anyway, so the cache ends up getting the
  5615.  information basically for free.  In those cases where a user is simply
  5616.  scrolling around viewing a buffer there is a high probability that this is
  5617.  sufficient to always provide the needed information.  The second thing we
  5618.  can do is be smart about invalidating the cache.
  5619.  
  5620.  TODO -- Be smart about invalidating the cache.  Potential places:
  5621.  
  5622.  + Insertions at end-of-line which don't cause line-wraps do not alter the
  5623.    starting positions of any display lines.  These types of buffer
  5624.    modifications should not invalidate the cache.  This is actually a large
  5625.    optimization for redisplay speed as well.
  5626.  
  5627.  + Buffer modifications frequently only affect the display of lines at and
  5628.    below where they occur.  In these situations we should only invalidate
  5629.    the part of the cache starting at where the modification occurs.
  5630.  
  5631.  In case you're wondering, the Second Golden Rule of Redisplay is not
  5632.  applicable.
  5633.  ****************************************************************************/
  5634.  
  5635. /* This will get used quite a bit so we don't want to be constantly
  5636.    allocating and freeing it. */
  5637. line_start_cache_dynarr *internal_cache;
  5638.  
  5639. /*****************************************************************************
  5640.  update_internal_cache_list
  5641.  
  5642.  Makes internal_cache represent the TYPE display structs and only the
  5643.  TYPE display structs.
  5644.  ****************************************************************************/
  5645. static void
  5646. update_internal_cache_list (struct window *w, int type)
  5647. {
  5648.   int line;
  5649.   display_line_dynarr *dla = window_display_lines (w, type);
  5650.  
  5651.   Dynarr_reset (internal_cache);
  5652.   for (line = 0; line < Dynarr_length (dla); line++)
  5653.     {
  5654.       struct display_line *dl = Dynarr_atp (dla, line);
  5655.  
  5656.       if (dl->modeline)
  5657.     continue;
  5658.       else
  5659.     {
  5660.       struct line_start_cache lsc;
  5661.  
  5662.       lsc.start = dl->bufpos;
  5663.       lsc.end = dl->end_bufpos;
  5664.       lsc.height = dl->ascent + dl->descent;
  5665.  
  5666.       Dynarr_add (internal_cache, lsc);
  5667.     }
  5668.     }
  5669. }
  5670.  
  5671. /*****************************************************************************
  5672.  validate_line_start_cache
  5673.  
  5674.  Reset the line cache if necessary.  This should be run at the
  5675.  beginning of any function which access the cache.
  5676.  ****************************************************************************/
  5677. static void
  5678. validate_line_start_cache (struct window *w)
  5679. {
  5680.   struct buffer *b = XBUFFER (w->buffer);
  5681.   struct frame *f = XFRAME (w->frame);
  5682.  
  5683.   if (!w->line_cache_validation_override)
  5684.     {
  5685.       /* f->extents_changed used to be in here because extent face and
  5686.          size changes can cause text shifting.  However, the extent
  5687.          covering the region is constantly having its face set and
  5688.          priority altered by the mouse code.  This means that the line
  5689.          start cache is constanty being invalidated.  This is bad
  5690.          since the mouse code also triggers heavy usage of the cache.
  5691.          Since it is an unlikely that f->extents being changed
  5692.          indicates that the cache really needs to be updated and if it
  5693.          does redisplay will catch it pretty quickly we no longer
  5694.          invalidate the cache if it is set.  This greatly speeds up
  5695.          dragging out regions with the mouse. */
  5696.       if (XINT (w->line_cache_last_updated) < BUF_MODIFF (b)
  5697.       || f->faces_changed
  5698.       || f->clip_changed)
  5699.     {
  5700.       Dynarr_reset (w->line_start_cache);
  5701.     }
  5702.     }
  5703. }
  5704.  
  5705. /*****************************************************************************
  5706.  line_start_cache_start
  5707.  
  5708.  Return the very first buffer position contained in the given window's
  5709.  cache, or -1 if the cache is empty.  Assumes that the cache is valid.
  5710.  ****************************************************************************/
  5711. static Bufpos
  5712. line_start_cache_start (struct window *w)
  5713. {
  5714.   line_start_cache_dynarr *cache = w->line_start_cache;
  5715.  
  5716.   if (!Dynarr_length (cache))
  5717.     return -1;
  5718.   else
  5719.     return (Dynarr_atp (cache, 0)->start);
  5720. }
  5721.  
  5722. /*****************************************************************************
  5723.  line_start_cache_end
  5724.  
  5725.  Return the very last buffer position contained in the given window's
  5726.  cache, or -1 if the cache is empty.  Assumes that the cache is valid.
  5727.  ****************************************************************************/
  5728. static Bufpos
  5729. line_start_cache_end (struct window *w)
  5730. {
  5731.   line_start_cache_dynarr *cache = w->line_start_cache;
  5732.  
  5733.   if (!Dynarr_length (cache))
  5734.     return -1;
  5735.   else
  5736.     return (Dynarr_atp (cache, Dynarr_length (cache) - 1)->end);
  5737. }
  5738.  
  5739. /*****************************************************************************
  5740.  point_in_line_start_cache
  5741.  
  5742.  Return the index of the line POINT is contained within in window W's line
  5743.  start cache.  It will enlarge the cache or move the cache window in order
  5744.  to have POINT be present in the cache.  MIN_PAST is a guarantee of the
  5745.  number of entries in the cache present on either side of POINT (unless a
  5746.  buffer boundary is hit).  If MIN_PAST is -1 then it will be treated as 0,
  5747.  but the cache window will not be allowed to shift.  Returns -1 if POINT
  5748.  cannot be found in the cache for any reason.
  5749.  ****************************************************************************/
  5750. int
  5751. point_in_line_start_cache (struct window *w, Bufpos point, int min_past)
  5752. {
  5753.   struct buffer *b = XBUFFER (w->buffer);
  5754.   line_start_cache_dynarr *cache = w->line_start_cache;
  5755.   unsigned int top, bottom, pos;
  5756.  
  5757.   validate_line_start_cache (w);
  5758.   w->line_cache_validation_override++;
  5759.  
  5760.   /* Let functions pass in negative values, but we still treat -1
  5761.      specially. */
  5762.   /* #### bogosity alert */
  5763.   if (min_past < 0 && min_past != -1)
  5764.     min_past = -min_past;
  5765.  
  5766.   if (!Dynarr_length (cache) || line_start_cache_start (w) > point
  5767.       || line_start_cache_end (w) < point)
  5768.     {
  5769.       int loop;
  5770.       int win_char_height = window_char_height (w, 1);
  5771.  
  5772.       /* Occasionally we get here with a 0 height
  5773.          window. find_next_newline_no_quit will abort if we pass it a
  5774.          count of 0 so handle that case. */
  5775.       if (!win_char_height)
  5776.     win_char_height = 1;
  5777.  
  5778.       if (!Dynarr_length (cache))
  5779.     {
  5780.       Bufpos from = find_next_newline_no_quit (b, point, -1);
  5781.       Bufpos to = find_next_newline_no_quit (b, from, win_char_height);
  5782.  
  5783.       update_line_start_cache (w, from, to, point, 0);
  5784.  
  5785.       if (!Dynarr_length (cache))
  5786.         {
  5787.           w->line_cache_validation_override--;
  5788.           return -1;
  5789.         }
  5790.     }
  5791.  
  5792.       assert (Dynarr_length (cache));
  5793.  
  5794.       loop = 0;
  5795.       while (line_start_cache_start (w) > point
  5796.          && (loop < cache_adjustment || min_past == -1))
  5797.     {
  5798.       Bufpos from, to;
  5799.  
  5800.       from = line_start_cache_start (w);
  5801.       if (from <= BUF_BEGV (b))
  5802.         break;
  5803.  
  5804.       from = find_next_newline_no_quit (b, from, -win_char_height);
  5805.       to = line_start_cache_end (w);
  5806.  
  5807.       update_line_start_cache (w, from, to, point, 0);
  5808.       loop++;
  5809.     }
  5810.  
  5811.       if (line_start_cache_start (w) > point)
  5812.     {
  5813.       Bufpos from, to;
  5814.  
  5815.       from = find_next_newline_no_quit (b, point, -1);
  5816.       if (from >= BUF_ZV (b))
  5817.         {
  5818.           to = find_next_newline_no_quit (b, from, -win_char_height);
  5819.           from = to;
  5820.           to = BUF_ZV (b);
  5821.         }
  5822.       else
  5823.         to = find_next_newline_no_quit (b, from, win_char_height);
  5824.  
  5825.       update_line_start_cache (w, from, to, point, 0);
  5826.     }
  5827.  
  5828.       loop = 0;
  5829.       while (line_start_cache_end (w) < point
  5830.          && (loop < cache_adjustment || min_past == -1))
  5831.     {
  5832.       Bufpos from, to;
  5833.  
  5834.       to = line_start_cache_end (w);
  5835.       if (to >= BUF_ZV (b))
  5836.         break;
  5837.  
  5838.       from = line_start_cache_end (w);
  5839.       to = find_next_newline_no_quit (b, from, win_char_height);
  5840.  
  5841.       update_line_start_cache (w, from, to, point, 0);
  5842.       loop++;
  5843.     }
  5844.  
  5845.       if (line_start_cache_end (w) < point)
  5846.     {
  5847.       Bufpos from, to;
  5848.  
  5849.       from = find_next_newline_no_quit (b, point, -1);
  5850.       if (from >= BUF_ZV (b))
  5851.         {
  5852.           to = find_next_newline_no_quit (b, from, -win_char_height);
  5853.           from = to;
  5854.           to = BUF_ZV (b);
  5855.         }
  5856.       else
  5857.         to = find_next_newline_no_quit (b, from, win_char_height);
  5858.  
  5859.       update_line_start_cache (w, from, to, point, 0);
  5860.     }
  5861.     }
  5862.  
  5863.   assert (Dynarr_length (cache));
  5864.  
  5865.   if (min_past == -1)
  5866.     min_past = 0;
  5867.  
  5868.   /* This could happen if the buffer is narrowed. */
  5869.   if (line_start_cache_start (w) > point
  5870.       || line_start_cache_end (w) < point)
  5871.     {
  5872.       w->line_cache_validation_override--;
  5873.       return -1;
  5874.     }
  5875.  
  5876. find_point_loop:
  5877.  
  5878.   top = Dynarr_length (cache) - 1;
  5879.   bottom = 0;
  5880.  
  5881.   while (1)
  5882.     {
  5883.       unsigned int new_pos;
  5884.       Bufpos start, end;
  5885.  
  5886.       pos = (bottom + top + 1) >> 1;
  5887.       start = Dynarr_atp (cache, pos)->start;
  5888.       end = Dynarr_atp (cache, pos)->end;
  5889.  
  5890.       if (point >= start && point <= end)
  5891.     {
  5892.       if (pos < min_past && line_start_cache_start (w) > BUF_BEGV (b))
  5893.         {
  5894.           Bufpos from =
  5895.         find_next_newline_no_quit (b, line_start_cache_start (w),
  5896.                        -min_past - 1);
  5897.           Bufpos to = line_start_cache_end (w);
  5898.  
  5899.           update_line_start_cache (w, from, to, point, 0);
  5900.           goto find_point_loop;
  5901.         }
  5902.       else if ((Dynarr_length (cache) - pos - 1) < min_past
  5903.            && line_start_cache_end (w) < BUF_ZV (b))
  5904.         {
  5905.           Bufpos from = line_start_cache_end (w);
  5906.           Bufpos to = find_next_newline_no_quit (b, from,
  5907.                              (min_past
  5908.                               ? min_past
  5909.                               : 1));
  5910.  
  5911.           update_line_start_cache (w, from, to, point, 0);
  5912.           goto find_point_loop;
  5913.         }
  5914.       else
  5915.         {
  5916.           w->line_cache_validation_override--;
  5917.           return pos;
  5918.         }
  5919.     }
  5920.       else if (point > end)
  5921.     bottom = pos + 1;
  5922.       else if (point < start)
  5923.     top = pos - 1;
  5924.       else
  5925.     abort ();
  5926.  
  5927.       new_pos = (bottom + top + 1) >> 1;
  5928.       if (pos == new_pos)
  5929.     {
  5930.       w->line_cache_validation_override--;
  5931.       return -1;
  5932.     }
  5933.     }
  5934. }
  5935.  
  5936. /*****************************************************************************
  5937.  point_would_be_visible
  5938.  
  5939.  Return a boolean indicating if POINT would be visible in window W if
  5940.  display of the window was to begin at STARTP.
  5941.  ****************************************************************************/
  5942. int
  5943. point_would_be_visible (struct window *w, Bufpos startp, Bufpos point)
  5944. {
  5945.   struct buffer *b = XBUFFER (w->buffer);
  5946.   int pixpos = 0;
  5947.   int bottom = WINDOW_TEXT_HEIGHT (w);
  5948.   int start_elt;
  5949.  
  5950.   /* If point is before the intended start it obviously can't be visible. */
  5951.   if (point < startp)
  5952.     return 0;
  5953.  
  5954.   /* If point or start are not in the accessible buffer range, then
  5955.      fail. */
  5956.   if (startp < BUF_BEGV (b) || startp > BUF_ZV (b)
  5957.       || point < BUF_BEGV (b) || point > BUF_ZV (b))
  5958.     {
  5959.       w->line_cache_validation_override--;
  5960.       return 0;
  5961.     }
  5962.  
  5963.   validate_line_start_cache (w);
  5964.   w->line_cache_validation_override++;
  5965.  
  5966.   start_elt = point_in_line_start_cache (w, startp, 0);
  5967.   if (start_elt == -1)
  5968.     {
  5969.       w->line_cache_validation_override--;
  5970.       return 0;
  5971.     }
  5972.  
  5973.   assert (line_start_cache_start (w) <= startp
  5974.       && line_start_cache_end (w) >= startp);
  5975.  
  5976.   while (1)
  5977.     {
  5978.       int height;
  5979.  
  5980.       /* Expand the cache if necessary. */
  5981.       if (start_elt == Dynarr_length (w->line_start_cache))
  5982.     {
  5983.       Bufpos old_startp =
  5984.         Dynarr_atp (w->line_start_cache, start_elt - 1)->start;
  5985.  
  5986.       start_elt = point_in_line_start_cache (w, old_startp,
  5987.                          window_char_height (w, 0));
  5988.  
  5989.       /* We've already actually processed old_startp, so increment
  5990.              immediately. */
  5991.       start_elt++;
  5992.  
  5993.       /* If this happens we didn't add any extra elements.  Bummer. */
  5994.       if (start_elt == Dynarr_length (w->line_start_cache))
  5995.         {
  5996.           w->line_cache_validation_override--;
  5997.           return 0;
  5998.         }
  5999.     }
  6000.  
  6001.       height = Dynarr_atp (w->line_start_cache, start_elt)->height;
  6002.  
  6003.       if (pixpos + height > bottom)
  6004.     {
  6005.       if (bottom - pixpos < VERTICAL_CLIP (w, 0))
  6006.         {
  6007.           w->line_cache_validation_override--;
  6008.           return 0;
  6009.         }
  6010.     }
  6011.  
  6012.       pixpos += height;
  6013.       if (point <= Dynarr_atp (w->line_start_cache, start_elt)->end)
  6014.     {
  6015.       w->line_cache_validation_override--;
  6016.       return 1;
  6017.     }
  6018.  
  6019.       start_elt++;
  6020.     }
  6021. }
  6022.  
  6023. /*****************************************************************************
  6024.  start_end_of_last_line
  6025.  
  6026.  For the given window W, if display starts at STARTP, what will be the
  6027.  buffer position at the beginning or end of the last line displayed.
  6028.  The end of the last line is also know as the window end position.
  6029.  
  6030.  #### With a little work this could probably be reworked as just a call to
  6031.  start_with_line_at_pixpos.
  6032.  ****************************************************************************/
  6033. static Bufpos
  6034. start_end_of_last_line (struct window *w, Bufpos startp, int end)
  6035. {
  6036.   struct buffer *b = XBUFFER (w->buffer);
  6037.   line_start_cache_dynarr *cache = w->line_start_cache;
  6038.   int pixpos = 0;
  6039.   int bottom = WINDOW_TEXT_HEIGHT (w);
  6040.   Bufpos cur_start;
  6041.   int start_elt;
  6042.  
  6043.   validate_line_start_cache (w);
  6044.   w->line_cache_validation_override++;
  6045.  
  6046.   if (startp < BUF_BEGV (b))
  6047.     startp = BUF_BEGV (b);
  6048.   else if (startp > BUF_ZV (b))
  6049.     startp = BUF_ZV (b);
  6050.   cur_start = startp;
  6051.  
  6052.   start_elt = point_in_line_start_cache (w, cur_start, 0);
  6053.   if (start_elt == -1)
  6054.     abort ();    /* this had better never happen */
  6055.  
  6056.   while (1)
  6057.     {
  6058.       int height = Dynarr_atp (cache, start_elt)->height;
  6059.  
  6060.       cur_start = Dynarr_atp (cache, start_elt)->start;
  6061.  
  6062.       if (pixpos + height > bottom)
  6063.     {
  6064.       /* Adjust for any possible clip. */
  6065.       if (bottom - pixpos < VERTICAL_CLIP (w, 0))
  6066.         start_elt--;
  6067.  
  6068.       if (start_elt < 0)
  6069.         {
  6070.           w->line_cache_validation_override--;
  6071.           if (end)
  6072.         return (BUF_ZV (b));
  6073.           else
  6074.         return (BUF_BEGV (b));
  6075.         }
  6076.       else
  6077.         {
  6078.           w->line_cache_validation_override--;
  6079.           if (end)
  6080.         return Dynarr_atp (cache, start_elt)->end;
  6081.           else
  6082.         return Dynarr_atp (cache, start_elt)->start;
  6083.         }
  6084.     }
  6085.  
  6086.       pixpos += height;
  6087.       start_elt++;
  6088.       if (start_elt == Dynarr_length (cache))
  6089.     {
  6090.       Bufpos from = line_start_cache_end (w);
  6091.       int win_char_height = window_char_height (w, 0);
  6092.       Bufpos to = find_next_newline_no_quit (b, from,
  6093.                          (win_char_height
  6094.                           ? win_char_height
  6095.                           : 1));
  6096.  
  6097.       /* We've hit the end of the bottom so that's what it is. */
  6098.       if (from >= BUF_ZV (b))
  6099.         {
  6100.           w->line_cache_validation_override--;
  6101.           return (BUF_ZV (b));
  6102.         }
  6103.  
  6104.       update_line_start_cache (w, from, to, BUF_PT (b), 0);
  6105.  
  6106.       /* Updating the cache invalidates any current indexes. */
  6107.       start_elt = point_in_line_start_cache (w, cur_start, -1) + 1;
  6108.     }
  6109.     }
  6110. }
  6111.  
  6112. /*****************************************************************************
  6113.  start_of_last_line
  6114.  
  6115.  For the given window W, if display starts at STARTP, what will be the
  6116.  buffer position at the beginning of the last line displayed.
  6117.  ****************************************************************************/
  6118. Bufpos
  6119. start_of_last_line (struct window *w, Bufpos startp)
  6120. {
  6121.   return start_end_of_last_line (w, startp, 0);
  6122. }
  6123.  
  6124. /*****************************************************************************
  6125.  end_of_last_line
  6126.  
  6127.  For the given window W, if display starts at STARTP, what will be the
  6128.  buffer position at the end of the last line displayed.  This is also
  6129.  know as the window end position.
  6130.  ****************************************************************************/
  6131. Bufpos
  6132. end_of_last_line (struct window *w, Bufpos startp)
  6133. {
  6134.   return start_end_of_last_line (w, startp, 1);
  6135. }
  6136.  
  6137. /*****************************************************************************
  6138.  start_with_line_at_pixpos
  6139.  
  6140.  For window W, what does the starting position have to be so that the line
  6141.  containing POINT will cover pixel position PIXPOS.
  6142.  ****************************************************************************/
  6143. Bufpos
  6144. start_with_line_at_pixpos (struct window *w, Bufpos point, int pixpos)
  6145. {
  6146.   struct buffer *b = XBUFFER (w->buffer);
  6147.   int cur_elt;
  6148.   Bufpos cur_pos;
  6149.   int pixheight = pixpos - WINDOW_TEXT_TOP (w);
  6150.  
  6151.   validate_line_start_cache (w);
  6152.   w->line_cache_validation_override++;
  6153.  
  6154.   cur_elt = point_in_line_start_cache (w, point, 0);
  6155.   while (1)
  6156.     {
  6157.       cur_pos = Dynarr_atp (w->line_start_cache, cur_elt)->start;
  6158.  
  6159.       pixheight -= Dynarr_atp (w->line_start_cache, cur_elt)->height;
  6160.  
  6161.       /* Do not take into account the value of vertical_clip here.
  6162.          That is the responsibility of the calling functions. */
  6163.       if (pixheight < 0)
  6164.     {
  6165.       w->line_cache_validation_override--;
  6166.       return cur_pos;
  6167.     }
  6168.  
  6169.       cur_elt--;
  6170.       if (cur_elt < 0)
  6171.     {
  6172.       Bufpos from, to;
  6173.       int win_char_height;
  6174.  
  6175.       if (cur_pos <= BUF_BEGV (b))
  6176.         {
  6177.           w->line_cache_validation_override--;
  6178.           return (BUF_BEGV (b));
  6179.         }
  6180.  
  6181.       win_char_height = window_char_height (w, 0);
  6182.       if (!win_char_height)
  6183.         win_char_height = 1;
  6184.  
  6185.       from = find_next_newline_no_quit (b, cur_pos, -win_char_height);
  6186.       to = line_start_cache_end (w);
  6187.       update_line_start_cache (w, from, to, point, 0);
  6188.  
  6189.       cur_elt = point_in_line_start_cache (w, cur_pos, 2) - 1;
  6190.       assert (cur_elt >= 0);
  6191.     }
  6192.     }
  6193. }
  6194.  
  6195. /*****************************************************************************
  6196.  start_with_point_on_display_line
  6197.  
  6198.  For window W, what does the starting position have to be so that the
  6199.  line containing point is on display line LINE.  If LINE is positive
  6200.  it is considered to be the number of lines from the top of the window
  6201.  (0 is the top line).  If it is negative the number is considered to
  6202.  be the number of lines from the bottom (-1 is the bottom line).
  6203. ****************************************************************************/
  6204. Bufpos
  6205. start_with_point_on_display_line (struct window *w, Bufpos point, int line)
  6206. {
  6207.   validate_line_start_cache (w);
  6208.   w->line_cache_validation_override++;
  6209.  
  6210.   if (line >= 0)
  6211.     {
  6212.       int cur_elt = point_in_line_start_cache (w, point, line);
  6213.  
  6214.       if (cur_elt - line < 0)
  6215.     cur_elt = 0;        /* Hit the top */
  6216.       else
  6217.     cur_elt -= line;
  6218.  
  6219.       w->line_cache_validation_override--;
  6220.       return (Dynarr_atp (w->line_start_cache, cur_elt)->start);
  6221.     }
  6222.   else
  6223.     {
  6224.       /* The calculated value of pixpos is correct for the bottom line
  6225.          or what we want when line is -1.  Therefore we subtract one
  6226.          because we have already handled one line. */
  6227.       int new_line = -line - 1;
  6228.       int cur_elt = point_in_line_start_cache (w, point, new_line);
  6229.       int pixpos = WINDOW_TEXT_BOTTOM (w);
  6230.       Bufpos retval, search_point;
  6231.  
  6232.       /* If scroll_on_clipped_lines is false, the last "visible" line of
  6233.       the window covers the pixel at WINDOW_TEXT_BOTTOM (w) - 1.
  6234.       If s_o_c_l is true, then we don't want to count a clipped 
  6235.       line, so back up from the bottom by the height of the line 
  6236.       containing point. */
  6237.       if (scroll_on_clipped_lines)
  6238.     pixpos -= Dynarr_atp (w->line_start_cache, cur_elt)->height;
  6239.       else
  6240.     pixpos -= 1;
  6241.  
  6242.       if (cur_elt + new_line >= Dynarr_length (w->line_start_cache))
  6243.     {
  6244.       /* Hit the bottom of the buffer. */
  6245.       struct frame *f = XFRAME (w->frame);
  6246.       struct device *d = XDEVICE (f->device);
  6247.       struct font_metric_info fm;
  6248.       int adjustment =
  6249.         (cur_elt + new_line) - Dynarr_length (w->line_start_cache) + 1;
  6250.  
  6251.       cur_elt = Dynarr_length (w->line_start_cache) - 1;
  6252.  
  6253.       DEVMETH (d, font_metric_info,
  6254.            (d, FACE_CACHE_ELEMENT_FONT (w, DEFAULT_INDEX), &fm));
  6255.       pixpos -= (adjustment * fm.height);
  6256.       if (pixpos < WINDOW_TEXT_TOP (w))
  6257.         pixpos = WINDOW_TEXT_TOP (w);
  6258.     }
  6259.       else
  6260.     cur_elt = cur_elt + new_line;
  6261.  
  6262.       search_point = Dynarr_atp (w->line_start_cache, cur_elt)->start;
  6263.  
  6264.       retval = start_with_line_at_pixpos (w, search_point, pixpos);
  6265.       w->line_cache_validation_override--;
  6266.       return retval;
  6267.     }
  6268. }
  6269.  
  6270. /*****************************************************************************
  6271.  update_line_start_cache
  6272.  
  6273.  This is used to speed up vertical scrolling by caching the known buffer
  6274.  starting positions for display lines.  This allows the scrolling routines
  6275.  to avoid costly calls to regenerate_window.  If NO_REGEN is true then it
  6276.  will only add the values in the DESIRED display structs which are in the
  6277.  given range.
  6278.  
  6279.  Note also that the FROM/TO values are minimums.  It is possible that this
  6280.  function will actually add information outside of the lines containing
  6281.  those positions.  This can't hurt but it could possibly help.
  6282.  
  6283.  #### We currently force the cache to have only 1 contiguous region.  It
  6284.  might help to make the cache a dynarr of caches so that we can cover more
  6285.  areas.  This might, however, turn out to be a lot of overhead for too
  6286.  little gain.
  6287.  ****************************************************************************/
  6288. static void
  6289. update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
  6290.              Bufpos point, int no_regen)
  6291. {
  6292.   struct buffer *b = XBUFFER (w->buffer);
  6293.   line_start_cache_dynarr *cache = w->line_start_cache;
  6294.   Bufpos low_bound, high_bound;
  6295.  
  6296.   validate_line_start_cache (w);
  6297.   w->line_cache_validation_override++;
  6298.   updating_line_start_cache = 1;
  6299.  
  6300.   if (from < BUF_BEGV (b))
  6301.     from = BUF_BEGV (b);
  6302.   if (to > BUF_ZV (b))
  6303.     to = BUF_ZV (b);
  6304.  
  6305.   if (from > to)
  6306.     {
  6307.       updating_line_start_cache = 0;
  6308.       w->line_cache_validation_override--;
  6309.       return;
  6310.     }
  6311.  
  6312.   if (Dynarr_length (cache))
  6313.     {
  6314.       low_bound = line_start_cache_start (w);
  6315.       high_bound = line_start_cache_end (w);
  6316.  
  6317.       /* Check to see if the desired range is already in the cache. */
  6318.       if (from >= low_bound && to <= high_bound)
  6319.     {
  6320.       updating_line_start_cache = 0;
  6321.       w->line_cache_validation_override--;
  6322.       return;
  6323.     }
  6324.  
  6325.       /* Check to make sure that the desired range is adjacent to the
  6326.      current cache.  If not, invalidate the cache. */
  6327.       if (to < low_bound || from > high_bound)
  6328.     {
  6329.       Dynarr_reset (cache);
  6330.       low_bound = high_bound = -1;
  6331.     }
  6332.     }
  6333.   else
  6334.     {
  6335.       low_bound = high_bound = -1;
  6336.     }
  6337.  
  6338.   w->line_cache_last_updated = make_number (BUF_MODIFF (b));
  6339.  
  6340.   /* This could be integrated into the next two sections, but it is easier
  6341.      to follow what's going on by having it separate. */
  6342.   if (no_regen)
  6343.     {
  6344.       Bufpos start, end;
  6345.  
  6346.       update_internal_cache_list (w, DESIRED_DISP);
  6347.       if (!Dynarr_length (internal_cache))
  6348.     {
  6349.       updating_line_start_cache = 0;
  6350.       w->line_cache_validation_override--;
  6351.       return;
  6352.     }
  6353.  
  6354.       start = Dynarr_atp (internal_cache, 0)->start;
  6355.       end =
  6356.     Dynarr_atp (internal_cache, Dynarr_length (internal_cache) - 1)->end;
  6357.  
  6358.       /* We aren't allowed to generate additional information to fill in
  6359.          gaps, so if the DESIRED structs don't overlap the cache, reset the
  6360.          cache. */
  6361.       if (Dynarr_length (cache))
  6362.     {
  6363.       if (end < low_bound || start > high_bound)
  6364.         Dynarr_reset (cache);
  6365.  
  6366.       /* #### What should really happen if what we are doing is
  6367.              extending a line (the last line)? */
  6368.       if (Dynarr_length (cache) == 1
  6369.           && Dynarr_length (internal_cache) == 1)
  6370.         Dynarr_reset (cache);
  6371.     }
  6372.  
  6373.       if (!Dynarr_length (cache))
  6374.     {
  6375.       Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0),
  6376.                Dynarr_length (internal_cache));
  6377.       updating_line_start_cache = 0;
  6378.       w->line_cache_validation_override--;
  6379.       return;
  6380.     }
  6381.  
  6382.       /* An extra check just in case the calling function didn't pass in
  6383.          the bounds of the DESIRED structs in the first place. */
  6384.       if (start >= low_bound && end <= high_bound)
  6385.     {
  6386.       updating_line_start_cache = 0;
  6387.       w->line_cache_validation_override--;
  6388.       return;
  6389.     }
  6390.  
  6391.       /* At this point we know that the internal cache partially overlaps
  6392.          the main cache. */
  6393.       if (start < low_bound)
  6394.     {
  6395.       int ic_elt = Dynarr_length (internal_cache) - 1;
  6396.       while (ic_elt >= 0)
  6397.         {
  6398.           if (Dynarr_atp (internal_cache, ic_elt)->start < low_bound)
  6399.         break;
  6400.           else
  6401.         ic_elt--;
  6402.         }
  6403.  
  6404.       if (!(ic_elt >= 0))
  6405.         {
  6406.           Dynarr_reset (cache);
  6407.           Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0),
  6408.                    Dynarr_length (internal_cache));
  6409.           updating_line_start_cache = 0;
  6410.           w->line_cache_validation_override--;
  6411.           return;
  6412.         }
  6413.  
  6414.       Dynarr_insert_many_at_start (cache, Dynarr_atp (internal_cache, 0),
  6415.                   ic_elt + 1);
  6416.     }
  6417.  
  6418.       if (end > high_bound)
  6419.     {
  6420.       int ic_elt = 0;
  6421.  
  6422.       while (ic_elt < Dynarr_length (internal_cache))
  6423.         {
  6424.           if (Dynarr_atp (internal_cache, ic_elt)->start > high_bound)
  6425.         break;
  6426.           else
  6427.         ic_elt++;
  6428.         }
  6429.  
  6430.       if (!(ic_elt < Dynarr_length (internal_cache)))
  6431.         {
  6432.           Dynarr_reset (cache);
  6433.           Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0),
  6434.                    Dynarr_length (internal_cache));
  6435.           updating_line_start_cache = 0;
  6436.           w->line_cache_validation_override--;
  6437.           return;
  6438.         }
  6439.  
  6440.       Dynarr_add_many (cache, Dynarr_atp (internal_cache, ic_elt),
  6441.                Dynarr_length (internal_cache) - ic_elt);
  6442.     }
  6443.  
  6444.       updating_line_start_cache = 0;
  6445.       w->line_cache_validation_override--;
  6446.       return;
  6447.     }
  6448.  
  6449.   if (!Dynarr_length (cache) || from < low_bound)
  6450.     {
  6451.       Bufpos startp = find_next_newline_no_quit (b, from, -1);
  6452.       int marker = 0;
  6453.       int old_lb = low_bound;
  6454.  
  6455.       while (startp < old_lb || low_bound == -1)
  6456.     {
  6457.       int ic_elt;
  6458.  
  6459.       regenerate_window (w, startp, point, CMOTION_DISP);
  6460.       update_internal_cache_list (w, CMOTION_DISP);
  6461.  
  6462.       /* If this assert is triggered then regenerate_window failed
  6463.              to layout a single line.  That is not supposed to be
  6464.              possible because we impose a minimum height on the buffer
  6465.              and override vertical clip when we are in here. */
  6466.       assert (Dynarr_length (internal_cache));
  6467.       assert (startp == Dynarr_atp (internal_cache, 0)->start);
  6468.  
  6469.       ic_elt = Dynarr_length (internal_cache) - 1;
  6470.       if (low_bound != -1)
  6471.         {
  6472.           while (ic_elt >= 0)
  6473.         {
  6474.           if (Dynarr_atp (internal_cache, ic_elt)->start < old_lb)
  6475.             break;
  6476.           else
  6477.             ic_elt--;
  6478.         }
  6479.         }
  6480.       assert (ic_elt >= 0);
  6481.  
  6482.       Dynarr_insert_many (cache, Dynarr_atp (internal_cache, 0),
  6483.                   ic_elt + 1, marker);
  6484.       marker += (ic_elt + 1);
  6485.  
  6486.       if (startp < low_bound || low_bound == -1)
  6487.         low_bound = startp;
  6488.       startp = Dynarr_atp (internal_cache, ic_elt)->end + 1;
  6489.       if (startp > BUF_ZV (b))
  6490.         {
  6491.           updating_line_start_cache = 0;
  6492.           w->line_cache_validation_override--;
  6493.           return;
  6494.         }
  6495.     }
  6496.     }
  6497.  
  6498.   assert (Dynarr_length (cache));
  6499.   assert (from >= low_bound);
  6500.  
  6501.   /* Readjust the high_bound to account for any changes made while
  6502.      correcting the low_bound. */
  6503.   high_bound = Dynarr_atp (cache, Dynarr_length (cache) - 1)->end;
  6504.  
  6505.   if (to > high_bound)
  6506.     {
  6507.       Bufpos startp = Dynarr_atp (cache, Dynarr_length (cache) - 1)->end + 1;
  6508.  
  6509.       do
  6510.     {
  6511.       regenerate_window (w, startp, point, CMOTION_DISP);
  6512.       update_internal_cache_list (w, CMOTION_DISP);
  6513.  
  6514.       /* See comment above about regenerate_window failing. */
  6515.       assert (Dynarr_length (internal_cache));
  6516.  
  6517.       Dynarr_add_many (cache, Dynarr_atp (internal_cache, 0),
  6518.                Dynarr_length (internal_cache));
  6519.       high_bound = Dynarr_atp (cache, Dynarr_length (cache) - 1)->end;
  6520.       startp = high_bound + 1;
  6521.     }
  6522.       while (to > high_bound);
  6523.     }
  6524.  
  6525.   updating_line_start_cache = 0;
  6526.   w->line_cache_validation_override--;
  6527.   assert (to <= high_bound);
  6528. }
  6529.  
  6530.  
  6531. /*****************************************************************************
  6532.  glyph_to_pixel_translation
  6533.  
  6534.  Given x and y coordinates in characters, relative to a window, return the
  6535.  pixel location corresponding to those coordinates.  The pixel location
  6536.  returned is the center of the given character position.  The pixel values
  6537.  are generated relative to the window, not the frame.
  6538.  
  6539.  The modeline is considered to be part of the window.
  6540.  ****************************************************************************/
  6541. void
  6542. glyph_to_pixel_translation (struct window *w, int char_x, int char_y,
  6543.                 int *pix_x, int *pix_y)
  6544. {
  6545.   struct frame *f = XFRAME (w->frame);
  6546.   struct device *d = XDEVICE (f->device);
  6547.   display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
  6548.   int num_disp_lines, modeline;
  6549.  
  6550.   /* If we get a bogus value indicating somewhere above or to the left of
  6551.      the window, use the first window line or character position
  6552.      instead. */
  6553.   if (char_y < 0)
  6554.     char_y = 0;
  6555.   if (char_x < 0)
  6556.     char_x = 0;
  6557.  
  6558.   num_disp_lines = Dynarr_length (dla);
  6559.   modeline = 0;
  6560.   if (num_disp_lines)
  6561.     {
  6562.       if (Dynarr_atp (dla, 0)->modeline)
  6563.     {
  6564.       num_disp_lines--;
  6565.       modeline = 1;
  6566.     }
  6567.     }
  6568.  
  6569.   /* First check if the y position intersects the display lines. */
  6570.   if (char_y < num_disp_lines)
  6571.     {
  6572.       struct display_line *dl = Dynarr_atp (dla, char_y + modeline);
  6573.       struct display_block *db = get_display_block_from_line (dl, TEXT);
  6574.  
  6575.       *pix_y = (dl->ypos - dl->ascent +
  6576.         ((unsigned int) (dl->ascent + dl->descent - dl->clip) >> 1));
  6577.  
  6578.       if (char_x < Dynarr_length (db->runes))
  6579.     {
  6580.       struct rune *rb = Dynarr_atp (db->runes, char_x);
  6581.  
  6582.       *pix_x = rb->xpos + (rb->width >> 1);
  6583.     }
  6584.       else
  6585.     {
  6586.       int last_rune = Dynarr_length (db->runes) - 1;
  6587.       struct rune *rb = Dynarr_atp (db->runes, last_rune);
  6588.       struct font_metric_info fm;
  6589.  
  6590.       DEVMETH (d, font_metric_info,
  6591.            (d, FACE_CACHE_ELEMENT_FONT (w, DEFAULT_INDEX), &fm));
  6592.  
  6593.       char_x -= last_rune;
  6594.  
  6595.       *pix_x = rb->xpos + rb->width;
  6596.       *pix_x += ((char_x - 1) * fm.width);
  6597.       *pix_x += (fm.width >> 1);
  6598.     }
  6599.     }
  6600.   else
  6601.     {
  6602.       /* It didn't intersect, so extrapolate.  #### For now, we include the
  6603.      modeline in this since we don't have true character positions in
  6604.      it. */
  6605.       struct font_metric_info fm;
  6606.  
  6607.       if (!Dynarr_length (w->face_cache_elements))
  6608.     reset_face_cache_elements (w);
  6609.  
  6610.       DEVMETH (d, font_metric_info,
  6611.            (d, FACE_CACHE_ELEMENT_FONT (w, DEFAULT_INDEX), &fm));
  6612.  
  6613.       char_y -= num_disp_lines;
  6614.  
  6615.       if (Dynarr_length (dla))
  6616.     {
  6617.       struct display_line *dl = Dynarr_atp (dla, Dynarr_length (dla) - 1);
  6618.       *pix_y = dl->ypos + dl->descent - dl->clip;
  6619.     }
  6620.       else
  6621.     *pix_y = WINDOW_TEXT_TOP (w);
  6622.  
  6623.       *pix_y += (char_y * fm.height);
  6624.       *pix_y += (fm.height >> 1);
  6625.  
  6626.       *pix_x = WINDOW_TEXT_LEFT (w);
  6627.       /* Don't adjust by one because this is still the unadjusted value. */
  6628.       *pix_x += (char_x * fm.width);
  6629.       *pix_x += (fm.width >> 1);
  6630.     }
  6631.  
  6632.   if (*pix_x > w->pixel_left + w->pixel_width)
  6633.     *pix_x = w->pixel_left + w->pixel_width;
  6634.   if (*pix_y > w->pixel_top + w->pixel_height)
  6635.     *pix_y = w->pixel_top + w->pixel_height;
  6636.  
  6637.   *pix_x -= w->pixel_left;
  6638.   *pix_y -= w->pixel_top;
  6639. }
  6640.  
  6641. /*****************************************************************************
  6642.  get_position_object
  6643.  
  6644.  Given a display line and a position, determine if there is a glyph
  6645.  there and return information about it if there is.
  6646.  ****************************************************************************/
  6647. static void
  6648. get_position_object (struct display_line *dl, Lisp_Object *obj, int x_coord,
  6649.              int *low_x_coord, int *high_x_coord)
  6650. {
  6651.   struct display_block *db;
  6652.   int elt;
  6653.   int block =
  6654.     get_next_display_block (dl->bounds, dl->display_blocks, x_coord, 0);
  6655.  
  6656.   /* We use get_next_display_block to get the actual display block
  6657.      that would be displayed at x_coord. */
  6658.  
  6659.   if (block == NO_BLOCK)
  6660.     return;
  6661.   else
  6662.     db = Dynarr_atp (dl->display_blocks, block);
  6663.  
  6664.   for (elt = 0; elt < Dynarr_length (db->runes); elt++)
  6665.     {
  6666.       struct rune *rb = Dynarr_atp (db->runes, elt);
  6667.  
  6668.       if (rb->xpos <= x_coord && x_coord < (rb->xpos + rb->width))
  6669.     {
  6670.       *obj = rb->extent;
  6671.       if (low_x_coord)
  6672.         *low_x_coord = rb->xpos;
  6673.       if (high_x_coord)
  6674.         *high_x_coord = rb->xpos + rb->width;
  6675.  
  6676.       return;
  6677.     }
  6678.     }
  6679. }
  6680.  
  6681. /*****************************************************************************
  6682.  pixel_to_glyph_translation
  6683.  
  6684.  Given x and y coordinates in pixels relative to a frame, return
  6685.  information about what is located under those coordinates.
  6686.  ****************************************************************************/
  6687.  
  6688. #define UPDATE_CACHE_RETURN                        \
  6689.   do {                                    \
  6690.     d->pixel_to_glyph_cache.valid = 1;                    \
  6691.     d->pixel_to_glyph_cache.low_x_coord = low_x_coord;            \
  6692.     d->pixel_to_glyph_cache.high_x_coord = high_x_coord;        \
  6693.     d->pixel_to_glyph_cache.low_y_coord = low_y_coord;            \
  6694.     d->pixel_to_glyph_cache.high_y_coord = high_y_coord;        \
  6695.     d->pixel_to_glyph_cache.frame = f;                    \
  6696.     d->pixel_to_glyph_cache.col = *col;                    \
  6697.     d->pixel_to_glyph_cache.row = *row;                    \
  6698.     d->pixel_to_glyph_cache.obj_x = *obj_x;                \
  6699.     d->pixel_to_glyph_cache.obj_y = *obj_y;                \
  6700.     d->pixel_to_glyph_cache.w = *w;                    \
  6701.     d->pixel_to_glyph_cache.bufpos = *bufpos;                \
  6702.     d->pixel_to_glyph_cache.closest = *closest;                \
  6703.     d->pixel_to_glyph_cache.obj = *obj;                    \
  6704.     d->pixel_to_glyph_cache.retval = position;                \
  6705.     return position;                            \
  6706.   } while (0)
  6707.  
  6708. int
  6709. pixel_to_glyph_translation (struct frame *f, int x_coord, int y_coord,
  6710.                 int *col, int *row, int *obj_x, int *obj_y,
  6711.                 struct window **w, Bufpos *bufpos,
  6712.                 Bufpos *closest, Lisp_Object *obj)
  6713. {
  6714.   struct device *d;
  6715.   struct pixel_to_glyph_translation_cache *cache;
  6716.   Lisp_Object window;
  6717.   int frm_left, frm_right, frm_top, frm_bottom;
  6718.   int low_x_coord, high_x_coord, low_y_coord, high_y_coord;
  6719.   int position = OVER_NOTHING;
  6720.   int device_check_failed = 0;
  6721.   display_line_dynarr *dla;
  6722.  
  6723.   /* This is a safety valve in case this got called with a frame in
  6724.      the middle of being deleted. */
  6725.   if (!DEVICEP (f->device) || !DEVICE_LIVE_P (XDEVICE (f->device)))
  6726.     device_check_failed = 1;
  6727.   else
  6728.     {
  6729.       d = XDEVICE (f->device);
  6730.       cache = &d->pixel_to_glyph_cache;
  6731.     }
  6732.  
  6733.   if (!device_check_failed
  6734.       && cache->valid
  6735.       && cache->frame == f
  6736.       && cache->low_x_coord <= x_coord
  6737.       && cache->high_x_coord > x_coord
  6738.       && cache->low_y_coord <= y_coord
  6739.       && cache->high_y_coord > y_coord)
  6740.     {
  6741.       *col = cache->col;
  6742.       *row = cache->row;
  6743.       *obj_x = cache->obj_x;
  6744.       *obj_y = cache->obj_y;
  6745.       *w = cache->w;
  6746.       *bufpos = cache->bufpos;
  6747.       *closest = cache->closest;
  6748.       *obj = cache->obj;
  6749.  
  6750.       return cache->retval;
  6751.     }
  6752.   else
  6753.     {
  6754.       *col = 0;
  6755.       *row = 0;
  6756.       *obj_x = 0;
  6757.       *obj_y = 0;
  6758.       *w = 0;
  6759.       *bufpos = 0;
  6760.       *closest = 0;
  6761.       *obj = Qnil;
  6762.  
  6763.       low_x_coord = x_coord;
  6764.       high_x_coord = x_coord + 1;
  6765.       low_y_coord = y_coord;
  6766.       high_y_coord = y_coord + 1;
  6767.     }
  6768.  
  6769.   if (device_check_failed)
  6770.     return OVER_NOTHING;
  6771.  
  6772.   frm_left = FRAME_LEFT_BORDER_END (f);
  6773.   frm_right = FRAME_RIGHT_BORDER_START (f);
  6774.   frm_top = FRAME_TOP_BORDER_END (f);
  6775.   frm_bottom = FRAME_BOTTOM_BORDER_START (f);
  6776.  
  6777.   /* Check if the mouse is outside of the text area actually used by
  6778.      redisplay. */
  6779.   if (y_coord < frm_top)
  6780.     {
  6781.       if (y_coord >= FRAME_TOP_BORDER_START (f))
  6782.     {
  6783.       low_y_coord = FRAME_TOP_BORDER_START (f);
  6784.       high_y_coord = frm_top;
  6785.       position = OVER_BORDER;
  6786.     }
  6787.       else if (y_coord >= 0)
  6788.     {
  6789.       low_y_coord = 0;
  6790.       high_y_coord = FRAME_TOP_BORDER_START (f);
  6791.       position = OVER_TOOLBAR;
  6792.     }
  6793.       else
  6794.     {
  6795.       low_y_coord = y_coord;
  6796.       high_y_coord = 0;
  6797.       position = OVER_OUTSIDE;
  6798.     }
  6799.     }
  6800.   else if (y_coord >= frm_bottom)
  6801.     {
  6802.       if (y_coord < FRAME_BOTTOM_BORDER_END (f))
  6803.     {
  6804.       low_y_coord = frm_bottom;
  6805.       high_y_coord = FRAME_BOTTOM_BORDER_END (f);
  6806.       position = OVER_BORDER;
  6807.     }
  6808.       else if (y_coord < FRAME_PIXHEIGHT (f))
  6809.     {
  6810.       low_y_coord = FRAME_BOTTOM_BORDER_END (f);
  6811.       high_y_coord = FRAME_PIXHEIGHT (f);
  6812.       position = OVER_TOOLBAR;
  6813.     }
  6814.       else
  6815.     {
  6816.       low_y_coord = FRAME_PIXHEIGHT (f);
  6817.       high_y_coord = y_coord;
  6818.       position = OVER_OUTSIDE;
  6819.     }
  6820.     }
  6821.  
  6822.   if (position != OVER_TOOLBAR && position != OVER_BORDER)
  6823.     {
  6824.       if (x_coord < frm_left)
  6825.     {
  6826.       if (x_coord >= FRAME_LEFT_BORDER_START (f))
  6827.         {
  6828.           low_x_coord = FRAME_LEFT_BORDER_START (f);
  6829.           high_x_coord = frm_left;
  6830.           position = OVER_BORDER;
  6831.         }
  6832.       else if (x_coord >= 0)
  6833.         {
  6834.           low_x_coord = 0;
  6835.           high_x_coord = FRAME_LEFT_BORDER_START (f);
  6836.           position = OVER_TOOLBAR;
  6837.         }
  6838.       else
  6839.         {
  6840.           low_x_coord = x_coord;
  6841.           high_x_coord = 0;
  6842.           position = OVER_OUTSIDE;
  6843.         }
  6844.     }
  6845.       else if (x_coord >= frm_right)
  6846.     {
  6847.       if (x_coord < FRAME_RIGHT_BORDER_END (f))
  6848.         {
  6849.           low_x_coord = frm_right;
  6850.           high_x_coord = FRAME_RIGHT_BORDER_END (f);
  6851.           position = OVER_BORDER;
  6852.         }
  6853.       else if (x_coord < FRAME_PIXWIDTH (f))
  6854.         {
  6855.           low_x_coord = FRAME_RIGHT_BORDER_END (f);
  6856.           high_x_coord = FRAME_PIXWIDTH (f);
  6857.           position = OVER_TOOLBAR;
  6858.         }
  6859.       else
  6860.         {
  6861.           low_x_coord = FRAME_PIXWIDTH (f);
  6862.           high_x_coord = x_coord;
  6863.           position = OVER_OUTSIDE;
  6864.         }
  6865.     }
  6866.     }
  6867.  
  6868.   if (position == OVER_TOOLBAR)
  6869.     {
  6870.       *obj = toolbar_button_at_pixpos (f, x_coord, y_coord);
  6871.       *w = 0;
  6872.       UPDATE_CACHE_RETURN;
  6873.     }
  6874.  
  6875.   /* We still have to return the window the pointer is next to and its
  6876.      relative y position even if it is outside the x boundary. */
  6877.   if (x_coord < frm_left)
  6878.     x_coord = frm_left;
  6879.   else if (x_coord > frm_right)
  6880.     x_coord = frm_right;
  6881.  
  6882.   /* Same in reverse. */
  6883.   if (y_coord < frm_top)
  6884.     y_coord = frm_top;
  6885.   else if (y_coord > frm_bottom)
  6886.     y_coord = frm_bottom;
  6887.  
  6888.   /* Find what window the given coordinates are actually in. */
  6889.   window = f->root_window;
  6890.   *w = find_window_by_pixel_pos (x_coord, y_coord, window);
  6891.  
  6892.   /* If we didn't find a window, we're done. */
  6893.   if (!*w)
  6894.     {
  6895.       UPDATE_CACHE_RETURN;
  6896.     }
  6897.   else if (position != OVER_NOTHING)
  6898.     {
  6899.       *closest = 0;
  6900.  
  6901.       if (high_y_coord <= frm_top || high_y_coord >= frm_bottom)
  6902.     {
  6903.       *w = 0;
  6904.       UPDATE_CACHE_RETURN;
  6905.     }
  6906.     }
  6907.  
  6908.   /* Check if the window is a minibuffer but isn't active. */
  6909.   if (MINI_WINDOW_P (*w) && !minibuf_level)
  6910.     {
  6911.       /* Must reset the window value since some callers will ignore
  6912.          the return value if it is set. */
  6913.       *w = 0;
  6914.       UPDATE_CACHE_RETURN;
  6915.     }
  6916.  
  6917.   dla = window_display_lines (*w, CURRENT_DISP);
  6918.  
  6919.   for (*row = 0; *row < Dynarr_length (dla); (*row)++)
  6920.     {
  6921.       int really_over_nothing = 0;
  6922.       struct display_line *dl = Dynarr_atp (dla, *row);
  6923.  
  6924.       if ((int) (dl->ypos - dl->ascent) <= y_coord
  6925.       && y_coord <= (int) (dl->ypos + dl->descent))
  6926.     {
  6927.       int check_margin_glyphs = 0;
  6928.       struct display_block *db = get_display_block_from_line (dl, TEXT);
  6929.       struct rune *rb = 0;
  6930.  
  6931.       if (x_coord < dl->bounds.left_white
  6932.           || x_coord >= dl->bounds.right_white)
  6933.         check_margin_glyphs = 1;
  6934.  
  6935.       low_y_coord = dl->ypos - dl->ascent;
  6936.       high_y_coord = dl->ypos + dl->descent + 1;
  6937.  
  6938.       if (position == OVER_BORDER
  6939.           || position == OVER_OUTSIDE
  6940.           || check_margin_glyphs)
  6941.         {
  6942.           int x_check, left_bound;
  6943.  
  6944.           if (check_margin_glyphs)
  6945.         {
  6946.           x_check = x_coord;
  6947.           left_bound = dl->bounds.left_white;
  6948.         }
  6949.           else
  6950.         {
  6951.           x_check = high_x_coord;
  6952.           left_bound = frm_left;
  6953.         }
  6954.  
  6955.           if (Dynarr_length (db->runes))
  6956.         {
  6957.           if (x_check <= left_bound)
  6958.             *closest = Dynarr_atp (db->runes, 0)->bufpos;
  6959.           else
  6960.             *closest =
  6961.               Dynarr_atp (db->runes,
  6962.                   Dynarr_length (db->runes) - 1)->bufpos;
  6963.  
  6964.           *closest += dl->offset;
  6965.         }
  6966.           else
  6967.         {
  6968.           /* #### What should be here. */
  6969.           *closest = 0;
  6970.           }
  6971.  
  6972.           if (check_margin_glyphs)
  6973.         {
  6974.           if (x_coord < dl->bounds.left_in
  6975.               || x_coord >= dl->bounds.right_in)
  6976.             {
  6977.               /* If we are over the outside margins then we
  6978.                          know the loop over the text block isn't going
  6979.                          to accomplish anything.  So we go ahead and
  6980.                          set what information we can right here and
  6981.                          return. */
  6982.               (*row)--;
  6983.               *obj_y = y_coord - (dl->ypos - dl->ascent);
  6984.               get_position_object (dl, obj, x_coord, &low_x_coord,
  6985.                        &high_x_coord);
  6986.  
  6987.               UPDATE_CACHE_RETURN;
  6988.             }
  6989.         }
  6990.           else
  6991.         UPDATE_CACHE_RETURN;
  6992.         }
  6993.  
  6994.       for (*col = 0; *col <= Dynarr_length (db->runes); (*col)++)
  6995.         {
  6996.           int past_end = (*col == Dynarr_length (db->runes));
  6997.  
  6998.           if (!past_end)
  6999.         rb = Dynarr_atp (db->runes, *col);
  7000.  
  7001.           if (past_end ||
  7002.           (rb->xpos <= x_coord && x_coord < rb->xpos + rb->width))
  7003.         {
  7004.           if (past_end)
  7005.             {
  7006.               (*col)--;
  7007.               rb = Dynarr_atp (db->runes, *col);
  7008.             }
  7009.  
  7010.           *bufpos = rb->bufpos + dl->offset;
  7011.           low_x_coord = rb->xpos;
  7012.           high_x_coord = rb->xpos + rb->width;
  7013.  
  7014.           if (rb->type == DGLYPH)
  7015.             {
  7016.               int elt = *col + 1;
  7017.  
  7018.               /* Find the first character after the glyph. */
  7019.               while (elt < Dynarr_length (db->runes))
  7020.             {
  7021.               if (Dynarr_atp (db->runes, elt)->type != DGLYPH)
  7022.                 {
  7023.                   *closest = (Dynarr_atp (db->runes, elt)->bufpos +
  7024.                       dl->offset);
  7025.                   break;
  7026.                 }
  7027.  
  7028.               elt++;
  7029.             }
  7030.  
  7031.               /* In this case we failed to find a non-glyph
  7032.                          character so we return the last position
  7033.                          displayed on the line. */
  7034.               if (elt == Dynarr_length (db->runes))
  7035.             {
  7036.               *closest = dl->end_bufpos + dl->offset;
  7037.               really_over_nothing = 1;
  7038.             }              
  7039.             }
  7040.           else
  7041.             *closest = rb->bufpos + dl->offset;
  7042.  
  7043.           if (dl->modeline)
  7044.             {
  7045.               *row = window_displayed_height (*w);
  7046.  
  7047.               if (position == OVER_NOTHING)
  7048.             position = OVER_MODELINE;
  7049.  
  7050.               UPDATE_CACHE_RETURN;
  7051.             }
  7052.           else if (past_end
  7053.                || (rb->type == CHAR && rb->object.ch == '\n'))
  7054.             {
  7055.               (*row)--;
  7056.               /* At this point we may have glyphs in the right
  7057.                          inside margin. */
  7058.               if (check_margin_glyphs)
  7059.             get_position_object (dl, obj, x_coord, &low_x_coord,
  7060.                          &high_x_coord);
  7061.               UPDATE_CACHE_RETURN;
  7062.             }
  7063.           else
  7064.             {
  7065.               (*row)--;
  7066.               *obj = rb->extent;
  7067.               *obj_x = x_coord - rb->xpos;
  7068.               *obj_y = y_coord - (dl->ypos - dl->ascent);
  7069.  
  7070.               /* At this point we may have glyphs in the left
  7071.                          inside margin. */
  7072.               if (check_margin_glyphs)
  7073.             get_position_object (dl, obj, x_coord, 0, 0);
  7074.  
  7075.               if (position == OVER_NOTHING && !really_over_nothing)
  7076.             position = OVER_TEXT;
  7077.  
  7078.               UPDATE_CACHE_RETURN;
  7079.             }
  7080.         }
  7081.         }
  7082.     }
  7083.     }
  7084.  
  7085.   *row = Dynarr_length (dla) - 1;
  7086.   if (FRAME_IS_WIN (f))
  7087.     {
  7088.       int bot_elt = Dynarr_length (dla) - 1;
  7089.  
  7090.       if (bot_elt >= 0)
  7091.     {
  7092.       struct display_line *dl = Dynarr_atp (dla, bot_elt);
  7093.       int adj_area = y_coord - (dl->ypos + dl->descent);
  7094.       struct font_metric_info fm;
  7095.  
  7096.       DEVMETH (d, font_metric_info,
  7097.            (d, FACE_CACHE_ELEMENT_FONT ((*w), DEFAULT_INDEX), &fm));
  7098.  
  7099.       *row += (adj_area / (fm.ascent + fm.descent));
  7100.     }
  7101.     }
  7102.  
  7103.   /* #### This should be checked out some more to determine what
  7104.      should really be going on. */
  7105.   if (!MARKERP ((*w)->start[CURRENT_DISP]))
  7106.     *closest = 0;
  7107.   else
  7108.     *closest = end_of_last_line (*w,
  7109.                  marker_position ((*w)->start[CURRENT_DISP]));
  7110.   *col = 0;
  7111.   UPDATE_CACHE_RETURN;
  7112. }
  7113. #undef UPDATE_CACHE_RETURN
  7114.  
  7115. DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, 0,
  7116.        "Clear frame FRAME and output again what is supposed to appear on it.")
  7117.      (frame)
  7118.      Lisp_Object frame;
  7119. {
  7120.   CHECK_LIVE_FRAME (frame, 0);
  7121.  
  7122.   XFRAME (frame)->clear = 1;
  7123.   redisplay_frame (XFRAME (frame));
  7124.  
  7125.   return Qnil;
  7126. }
  7127.  
  7128. DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 1, 0,
  7129.        "Redraw all frames on DEVICE marked as having their image garbled.\n\
  7130. DEVICE defaults to the selected device.\n\
  7131. If DEVICE is t, all devices will have their frames checked.")
  7132.      (device)
  7133.      Lisp_Object device;
  7134. {
  7135.   if (EQ (device, Qt))
  7136.     redisplay ();
  7137.   else
  7138.     redisplay_device (get_device (device));
  7139.  
  7140.   return Qnil;
  7141. }
  7142.  
  7143. /* Big lie.  Big lie.  This will force all modelines to be updated
  7144.    regardless if the all flag is set or not.  It remains in existence
  7145.    solely for backwards compatibility. */
  7146. DEFUN ("redraw-modeline", Fredraw_modeline, Sredraw_modeline, 0, 1, 0,
  7147.        "Force the modeline of the current buffer to be redisplayed.\n\
  7148. With optional non-nil ALL, force redisplay of all modelines.")
  7149.        (all)
  7150.        Lisp_Object all;
  7151. {
  7152.   MARK_MODELINE_CHANGED;
  7153.   return Qnil;
  7154. }
  7155.  
  7156. DEFUN ("force-redisplay", Fforce_redisplay, Sforce_redisplay, 0, 0, "",
  7157.   "Force an immediate redisplay of all frames.\n\
  7158. Will still cause a redisplay when there is input pending (unlike when\n\
  7159. the display is updated from `next-event').  This function differs from\n\
  7160. `redraw-display' in that it causes an immediate, visible update of the\n\
  7161. display's contents.  Unlike `redraw-frame' or `recenter', it does not\n\
  7162. mark any frame's current contents as invalid.")
  7163.      ()
  7164. {
  7165.   /* redisplay() can't throw, right?  It better not ... */
  7166.   disable_preemption++;
  7167.   redisplay ();
  7168.   disable_preemption--;
  7169.   return Qnil;
  7170. }
  7171.  
  7172. DEFUN ("force-cursor-redisplay", Fforce_cursor_redisplay,
  7173.        Sforce_cursor_redisplay, 0, 0, 0,
  7174.   "Force an immediate update of the cursor on the selected frame.")
  7175.       ()
  7176. {
  7177.   redisplay_redraw_cursor (get_frame (Qnil), 1);
  7178.   return Qnil;
  7179. }
  7180.  
  7181.  
  7182. static void
  7183. margin_width_changed_in_frame (Lisp_Object specifier, struct frame *f,
  7184.                    Lisp_Object oldval)
  7185. {
  7186.   /* Nothing to be done? */
  7187. }
  7188.  
  7189. int
  7190. redisplay_variable_changed (Lisp_Object sym, Lisp_Object *val,
  7191.                 struct buffer *b, int flags)
  7192. {
  7193.   /* #### clip_changed should really be renamed something like
  7194.      global_redisplay_change. */
  7195.   MARK_CLIP_CHANGED;
  7196.   return 0;
  7197. }
  7198.  
  7199.  
  7200. void
  7201. init_redisplay (void)
  7202. {
  7203.   disable_preemption = 0;
  7204.   preemption_count = 0;
  7205.   max_preempts = INIT_MAX_PREEMPTS;
  7206.  
  7207.   if (!initialized)
  7208.     {
  7209.       mode_spec = Dynarr_new (char);
  7210.       mode_string_buffer = Dynarr_new (Emchar);
  7211.       internal_cache = Dynarr_new (struct line_start_cache);
  7212.     }
  7213.  
  7214.   /* window system is nil when in -batch mode */
  7215.   if (!initialized || noninteractive)
  7216.     return;
  7217.  
  7218.   /* If the user wants to use a window system, we shouldn't bother
  7219.      initializing the terminal.  This is especially important when the
  7220.      terminal is so dumb that emacs gives up before and doesn't bother
  7221.      using the window system.
  7222.  
  7223.      If the DISPLAY environment variable is set, try to use X, and die
  7224.      with an error message if that doesn't work.  */
  7225.  
  7226. #ifdef HAVE_X_WINDOWS
  7227.   if (!strcmp (display_use, "x"))
  7228.     {
  7229.       /* Some stuff checks this way early. */
  7230.       Vwindow_system = Qx;
  7231.       Vinitial_window_system = Qx;
  7232.       Vwindow_system_version = make_number (11);
  7233.       return;
  7234.     }
  7235. #endif
  7236. #ifdef HAVE_NEXTSTEP
  7237.   if (!strcmp (display_use, "ns"))
  7238.     {
  7239.       Vwindow_system = Qns;
  7240.       Vinitial_window_system = Qns;
  7241.       Vwindow_system_version = Qzero;
  7242.       return;
  7243.     }        
  7244. #endif
  7245.  
  7246.   /* If no window system has been specified, try to use the terminal.  */
  7247.   if (!isatty (0))
  7248.     {
  7249.       stderr_out ("XEmacs: standard input is not a tty\n");
  7250.       exit (1);
  7251.     }
  7252.  
  7253.   /* Look at the TERM variable */
  7254.   if (!getenv ("TERM"))
  7255.     {
  7256.       stderr_out ("Please set the environment variable TERM; see tset(1).\n");
  7257.       exit (1);
  7258.     }
  7259.  
  7260.   Vwindow_system_version = Qnil;
  7261.   Vinitial_window_system = Qtty;
  7262. }
  7263.  
  7264. void
  7265. syms_of_redisplay (void)
  7266. {
  7267.   defsymbol (&Qcursor_in_echo_area, "cursor-in-echo-area");
  7268. #if 0
  7269. /* #### Chuck says: I think this needs more thought.
  7270.    Think about this for 19.14. */
  7271.   defsymbol (&Qpre_redisplay_hook, "pre-redisplay-hook");
  7272.   defsymbol (&Qpost_redisplay_hook, "post-redisplay-hook");
  7273. #endif
  7274.   defsymbol (&Qdisplay_warning_buffer, "display-warning-buffer");
  7275.  
  7276.   defsubr (&Sredraw_frame);
  7277.   defsubr (&Sredraw_display);
  7278.   defsubr (&Sredraw_modeline);
  7279.   defsubr (&Sforce_redisplay);
  7280.   defsubr (&Sforce_cursor_redisplay);
  7281.   defsubr (&Sredisplay_echo_area);
  7282. }
  7283.  
  7284. void
  7285. vars_of_redisplay (void)
  7286. {
  7287. #if 0
  7288.   staticpro (&last_arrow_position);
  7289.   staticpro (&last_arrow_string);
  7290.   last_arrow_position = Qnil;
  7291.   last_arrow_string = Qnil;
  7292. #endif
  7293.  
  7294.   updating_line_start_cache = 0;
  7295.  
  7296.   /* #### Probably temporary */
  7297.   DEFVAR_INT ("redisplay-cache-adjustment", &cache_adjustment,
  7298.     "(Temporary) Setting this will impact the performance of the internal\n\
  7299. line start cache.");
  7300.   cache_adjustment = 2;
  7301.  
  7302.   DEFVARINT_MAGIC ("pixel-vertical-clip-threshold", &vertical_clip,
  7303.     "Minimum pixel height for clipped bottom display line.\n\
  7304. A clipped line shorter than this won't be displayed.",
  7305.            redisplay_variable_changed);
  7306.   vertical_clip = 5;
  7307.  
  7308.   DEFVARINT_MAGIC ("pixel-horizontal-clip-threshold", &horizontal_clip,
  7309.     "Minimum visible area for clipped glyphs at right boundary.\n\
  7310. Clipped glyphs shorter than this won't be displayed.\n\
  7311. Only pixmap glyph instances are currently allowed to be clipped.",
  7312.           redisplay_variable_changed);
  7313.   horizontal_clip = 5;
  7314.  
  7315.   DEFVAR_LISP ("global-mode-string", &Vglobal_mode_string,
  7316.     "String displayed by modeline-format's \"%m\" specification.");
  7317.   Vglobal_mode_string = Qnil;
  7318.  
  7319.   DEFVARLISP_MAGIC ("overlay-arrow-position", &Voverlay_arrow_position,
  7320.     "Marker for where to display an arrow on top of the buffer text.\n\
  7321. This must be the beginning of a line in order to work.\n\
  7322. See also `overlay-arrow-string'.", redisplay_variable_changed);
  7323.   Voverlay_arrow_position = Qnil;
  7324.  
  7325.   DEFVARLISP_MAGIC ("overlay-arrow-string", &Voverlay_arrow_string,
  7326.     "String to display as an arrow.  See also `overlay-arrow-position'.",
  7327.             redisplay_variable_changed);
  7328.   Voverlay_arrow_string = Qnil;
  7329.  
  7330.   DEFVAR_INT ("scroll-step", &scroll_step,
  7331.     "*The number of lines to try scrolling a window by when point moves out.\n\
  7332. If that fails to bring point back on frame, point is centered instead.\n\
  7333. If this is zero, point is always centered after it moves off frame.");
  7334.  
  7335.   DEFVARBOOL_MAGIC ("truncate-partial-width-windows",
  7336.            &truncate_partial_width_windows,
  7337.  "*Non-nil means truncate lines in all windows less than full frame wide.",
  7338.             redisplay_variable_changed);
  7339.   truncate_partial_width_windows = 1;
  7340.  
  7341.   DEFVAR_BOOL ("line-number-mode", &line_number_mode,
  7342.  "*Whether to display line numbers in the modeline.");
  7343.   line_number_mode = 0;
  7344.  
  7345.   DEFVAR_BOOL ("visible-bell", &visible_bell,
  7346.     "*Non-nil means try to flash the frame to represent a bell.");
  7347.   visible_bell = 0;
  7348.  
  7349.   DEFVAR_BOOL ("no-redraw-on-reenter", &no_redraw_on_reenter,
  7350.     "*Non-nil means no need to redraw entire frame after suspending.\n\
  7351. A non-nil value is useful if the terminal can automatically preserve\n\
  7352. Emacs's frame display when you reenter Emacs.\n\
  7353. It is up to you to set this variable if your terminal can do that.");
  7354.   no_redraw_on_reenter = 0;
  7355.  
  7356.   /* #### This should be removed in 19.14 */
  7357.   DEFVAR_LISP ("window-system", &Vwindow_system,
  7358.     "A symbol naming the window-system under which Emacs is running,\n\
  7359. such as `x', or nil if emacs is running on an ordinary terminal.\n\
  7360. This variable is OBSOLETE and will be removed in a future version.");
  7361.   Vwindow_system = Qnil;
  7362.  
  7363.   /* #### Temporary shit until window-system is eliminated. */
  7364.   DEFVAR_LISP ("initial-window-system", &Vinitial_window_system,
  7365.     "DON'T TOUCH");
  7366.   Vinitial_window_system = Qnil;
  7367.  
  7368.   DEFVAR_LISP ("window-system-version", &Vwindow_system_version,
  7369.     "The version number of the window system in use.\n\
  7370. For X windows, this is 10 or 11.");
  7371.   Vwindow_system_version = Qnil;
  7372.  
  7373.   DEFVAR_BOOL ("cursor-in-echo-area", &cursor_in_echo_area,
  7374.     "Non-nil means put cursor in minibuffer, at end of any message there.");
  7375.   cursor_in_echo_area = 0;
  7376.  
  7377.   /* #### Shouldn't this be generalized as follows:
  7378.  
  7379.      if nil, use block cursor.
  7380.      if a number, use a bar cursor of that width.
  7381.      Otherwise, use a 1-pixel bar cursor.
  7382.  
  7383.      #### Or better yet, this variable should be trashed entirely
  7384.      (use a Lisp-magic variable to maintain compatibility)
  7385.      and a specifier `cursor-shape' added, which allows a block
  7386.      cursor, a bar cursor, a flashing block or bar cursor,
  7387.      maybe a caret cursor, etc. */
  7388.  
  7389.   DEFVAR_LISP ("bar-cursor", &Vbar_cursor,
  7390.   "Use vertical bar cursor if non-nil.  If t width is 1 pixel, otherwise 2.");
  7391.   Vbar_cursor = Qnil;
  7392.  
  7393. #if 0
  7394. /* #### Chuck says: I think this needs more thought.
  7395.    Think about this for 19.14. */
  7396.   DEFVAR_LISP ("pre-redisplay-hook", &Vpre_redisplay_hook,
  7397.      "Function or functions to run before every redisplay.\n\
  7398. Functions on this hook must be careful to avoid signalling errors!");
  7399.   Vpre_redisplay_hook = Qnil;
  7400.  
  7401.   DEFVAR_LISP ("post-redisplay-hook", &Vpost_redisplay_hook,
  7402.      "Function or functions to run after every redisplay.\n\
  7403. Functions on this hook must be careful to avoid signalling errors!");
  7404.   Vpost_redisplay_hook = Qnil;
  7405. #endif
  7406.  
  7407.   DEFVAR_INT ("display-warning-tick", &display_warning_tick,
  7408.      "Bump this to tell the C code to call `display-warning-buffer'\n\
  7409. at next redisplay.  You should not normally change this; the function\n\
  7410. `display-warning' automatically does this at appropriate times.");
  7411.   display_warning_tick = 0;
  7412.  
  7413.   DEFVAR_BOOL ("inhibit-warning-display", &inhibit_warning_display,
  7414.      "Non-nil means inhibit display of warning messages.\n\
  7415. You should *bind* this, not set it.  Any pending warning messages\n\
  7416. will be displayed when the binding no longer applies.");
  7417.   /* reset to 0 by startup.el after the splash screen has displayed.
  7418.      This way, the warnings don't obliterate the splash screen. */
  7419.   inhibit_warning_display = 1;
  7420. }
  7421.  
  7422. void
  7423. specifier_vars_of_redisplay (void)
  7424. {
  7425.   DEFVAR_SPECIFIER ("left-margin-width", &Vleft_margin_width,
  7426.     "*Width of left margin.\n\
  7427. This is a specifier; use `set-specifier' to change it.");
  7428.   Vleft_margin_width = Fmake_specifier (Qnatnum);
  7429.   set_specifier_fallback
  7430.     (Vleft_margin_width,
  7431.      list1 (Fcons (Qnil, Qzero)));
  7432.   set_specifier_caching (Vleft_margin_width,
  7433.              slot_offset (struct window, left_margin_width),
  7434.              some_window_value_changed,
  7435.              slot_offset (struct frame, left_margin_width),
  7436.              margin_width_changed_in_frame);
  7437.  
  7438.   DEFVAR_SPECIFIER ("right-margin-width", &Vright_margin_width,
  7439.     "*Width of right margin.\n\
  7440. This is a specifier; use `set-specifier' to change it.");
  7441.   Vright_margin_width = Fmake_specifier (Qnatnum);
  7442.   set_specifier_fallback
  7443.     (Vright_margin_width,
  7444.      list1 (Fcons (Qnil, Qzero)));
  7445.   set_specifier_caching (Vright_margin_width,
  7446.              slot_offset (struct window, right_margin_width),
  7447.              some_window_value_changed,
  7448.              slot_offset (struct frame, right_margin_width),
  7449.              margin_width_changed_in_frame);
  7450.  
  7451.   DEFVAR_SPECIFIER ("minimum-line-ascent", &Vminimum_line_ascent,
  7452.     "*Minimum ascent height of lines.\n\
  7453. This is a specifier; use `set-specifier' to change it.");
  7454.   Vminimum_line_ascent = Fmake_specifier (Qnatnum);
  7455.   set_specifier_fallback (Vminimum_line_ascent,
  7456.               list1 (Fcons (Qnil, Qzero)));
  7457.   set_specifier_caching (Vminimum_line_ascent,
  7458.              slot_offset (struct window,
  7459.                       minimum_line_ascent),
  7460.              some_window_value_changed,
  7461.              0, 0);
  7462.  
  7463.   DEFVAR_SPECIFIER ("minimum-line-descent", &Vminimum_line_descent,
  7464.     "*Minimum descent height of lines.\n\
  7465. This is a specifier; use `set-specifier' to change it.");
  7466.   Vminimum_line_descent = Fmake_specifier (Qnatnum);
  7467.   set_specifier_fallback (Vminimum_line_descent,
  7468.               list1 (Fcons (Qnil, Qzero)));
  7469.   set_specifier_caching (Vminimum_line_descent,
  7470.              slot_offset (struct window,
  7471.                       minimum_line_descent),
  7472.              some_window_value_changed,
  7473.              0, 0);
  7474.  
  7475.   DEFVAR_SPECIFIER ("use-left-overflow", &Vuse_left_overflow,
  7476.     "*Non-nil means use the left outside margin as extra whitespace when\n\
  7477. displaying 'whitespace or 'inside-margin glyphs.\n\
  7478. This is a specifier; use `set-specifier' to change it.");
  7479.   Vuse_left_overflow = Fmake_specifier (Qboolean);
  7480.   set_specifier_fallback (Vuse_left_overflow,
  7481.               list1 (Fcons (Qnil, Qnil)));
  7482.   set_specifier_caching (Vuse_left_overflow,
  7483.              slot_offset (struct window,
  7484.                       use_left_overflow),
  7485.              some_window_value_changed,
  7486.              0, 0);
  7487.  
  7488.   DEFVAR_SPECIFIER ("use-right-overflow", &Vuse_right_overflow,
  7489.     "*Non-nil means use the right outside margin as extra whitespace when\n\
  7490. displaying 'whitespace or 'inside-margin glyphs.\n\
  7491. This is a specifier; use `set-specifier' to change it.");
  7492.   Vuse_right_overflow = Fmake_specifier (Qboolean);
  7493.   set_specifier_fallback (Vuse_right_overflow,
  7494.               list1 (Fcons (Qnil, Qnil)));
  7495.   set_specifier_caching (Vuse_right_overflow,
  7496.              slot_offset (struct window,
  7497.                       use_right_overflow),
  7498.              some_window_value_changed,
  7499.              0, 0);
  7500. }
  7501.